跳到主要内容

04 · 横切设施 · 巧妙之处 · 边界 · 代码地图

本章讲什么: 前三章是主线(Agent / Crew / Flow);这章讲贯穿它们的基础设施(LLM、记忆、事件、提示词组装),再提炼可借鉴的设计、诚实列出边界,最后给跳转用的代码地图。

4.1 LLM 抽象层

CrewAI 不绑死某家模型,而是有一层 BaseLLM(llms/base_llm.py)和默认实现 LLM(llm.py:? 处定义 class LLM)。LLM 底层走 litellm(统一上百家供应商 API 的库)。

一个真实的工程细节:litellm 被懒加载。因为 litellm 在 import 时会执行 dotenv.load_dotenv(),可能有副作用,所以 CrewAI 用 _ensure_litellm() 在首次用到时才加载(llm.py:74-156):

# llm.py:113-123(摘)
def _ensure_litellm() -> bool:
"""Lazy-load litellm on first use. Returns True if available."""
global _litellm_loaded, LITELLM_AVAILABLE
if _litellm_loaded:
return LITELLM_AVAILABLE
...

LLM 还向上层暴露能力查询:supports_function_calling()(决定走原生还是 ReAct,见 01 章)、supports_stop_words()supports_multimodal()supports_response_schema(llm.py)。这层「能力探测」让上层循环能因模型而异地选路径。

4.2 提示词怎么组装

Agent 的系统提示词由 Prompts.task_execution() 拼装(utilities/prompts.py:74-109)。它从「片段(slice)」拼起:role_playing(角色扮演,把 role/goal/backstory 填进去)、toolsno_tools、再加任务片段(task / native_task / task_no_tools)。

两种产物(utilities/prompts.py:12-35):

  • SystemPromptResult:分 system / user 两条消息(当模型适合用 system prompt)。
  • StandardPromptResult:合成单条 prompt

这解释了 01 章 _setup_messages 里为何要分别处理 "system" in self.prompt 与否(agents/crew_agent_executor.py:182-204)。提示词里是否包含 tools 片段,直接决定 LLM 会不会以 ReAct 文本格式调工具。

4.3 统一记忆(Memory)

memory/unified_memory.pyMemory(:76)是一套重新设计的记忆系统,docstring 自述其特点(:76-82):

Uses LLM to infer scope, categories, importance on save. Uses RecallFlow for adaptive-depth recall.

拆成两条线:

写入(remember)用 LLM 分析。 remember(...)(:430)存一条记忆时,LLM 会推断它的 scope(作用域)、category、importance。还有consolidation(合并):若新记忆与已有记忆相似度超过 consolidation_threshold(默认 0.85),触发合并而非重复存(:116-123)。

读取(recall)自适应深度。 recall(...)(:681)用一个 RecallFlow(本身是个 Flow!memory/recall_flow.py)做召回:先快速检索,若置信度低于阈值(confidence_threshold_low 默认 0.5)则触发更深的 LLM 驱动探索(exploration_budget 轮)。最终相关性是 recency / semantic / importance 三者加权(默认 0.3/0.5/0.2,:100-111)的复合分。

默认存储后端是 LanceDB(:92-95),embedder 默认 OpenAI。记忆可挂在 Crew 上,也可作为工具(recall/remember)注入给 Agent(crew.py:1761-1773 _add_memory_tools)。

注:本节据类字段与方法签名描述其结构;完整的召回评分与合并算法未逐行走读。

4.4 事件总线

crewai_event_bus(events/event_bus.py,class CrewAIEventsBus :94)是一个全局发布订阅总线。全流程关键节点都 emit 事件:CrewKickoffFailedEventTaskStartedEvent/TaskCompletedEventToolUsageStartedEvent/Finished/ErrorAgentLogsStartedEvent 等。

bus.on(EventType)(handler) 订阅(:244),bus.emit(source, event)(:570)发布。它支持运行时作用域(_enter_runtime_scope / _exit_runtime_scope),kickoff 进出时管理(crew.py:10331069)。可观测性(tracing)、verbose 日志、评测监听器都挂在这条总线上,做到了「核心逻辑不感知监听者」的解耦。

4.5 巧妙之处(可借鉴的技术)

  • 协作降维成工具调用。 多 Agent 委派不是另起一套调度,而是把「派活给同事」做成一个普通工具(DelegateWorkTool),复用 Agent 的工具循环(tools/agent_tools/agent_tools.py:2602 章 §2.5)。新机制最小化。
  • 两套范式互相嵌套,连执行器都跑在 Flow 上。 AgentExecutor(Flow[...], BaseAgentExecutor)(experimental/agent_executor.py:164)——最底层的 Agent 循环也被表达成 Flow。(01 章 §1.8、03 章 §3.8)
  • 原生→文本的运行时降级。 模型声称支持 function calling 但实际不行时,当场切回 ReAct 而非失败(crew_agent_executor.py:576-579)。
  • 每轮只执行一个原生工具调用 + 反思。 串行 + 反思保证 LLM 能基于结果调整,只有在无特殊工具的多调用批次才并行(crew_agent_executor.py:667-784)。
  • JSON 容错。 LLM 吐的工具参数常是坏 JSON,_safe_repair_jsonjson_repair 修复,修不好就原样返回而非崩溃(parser.py:161-179)。
  • 缓存断点对齐 ReAct 循环。 _setup_messages 在 system / user 提示词末尾打 prompt-cache 断点,跨循环迭代复用稳定前缀(crew_agent_executor.py:189-199)。
  • litellm 懒加载 规避其 import 副作用(llm.py:113)。

4.6 边界与局限(诚实)

  • consensual 流程未实现。 Process 里它还是注释掉的 TODO(process.py);只有 sequentialhierarchical 能用,其余 raise NotImplementedError(crew.py:1042)。
  • CrewAgentExecutor 已弃用。 旧执行器构造即发 DeprecationWarning,将来会移除;新默认是实验性的 AgentExecutor(crew_agent_executor.py:145-151)。即「当前最稳的循环代码」与「未来的循环代码」处于过渡期。
  • 经理 Agent 不能带工具。 层级模式下给 manager 传普通工具会直接抛异常(crew.py:1498-1505)——这是刻意约束,经理只负责调度。
  • 强依赖 LLM 守规矩。 ReAct 路径完全依赖 LLM 输出可解析的 Action/Final Answer 格式;格式错就靠「喂回纠错 + 重试」,但仍可能在 max_iter 内耗尽(crew_agent_executor.py:462-466)。
  • 记忆默认要外部依赖。 统一记忆默认用 LanceDB + OpenAI embedding,且写入/召回都可能额外打 LLM,成本与延迟需自己权衡(memory/unified_memory.py:88-95)。
  • 大量运行期依赖外部服务(litellm、各供应商、tracing)。框架本身的「智能」全在编排;真正的能力来自所接的模型。

4.7 横向对比(同 shelf 兄弟项目)

维度CrewAI典型对照
核心隐喻「角色化队伍(Crew)」+「事件流程(Flow)」双范式LangGraph 单一「图」范式;AutoGen 「会话式多 Agent」
多 Agent 协作委派/提问作为工具,或经理调度AutoGen 靠 Agent 间消息往返
控制 vs 自治显式二分:Crew 自治 / Flow 可控,可嵌套LangGraph 偏可控,自治需自己拼
模型接入litellm 统一上百家各家 SDK 直连或各自抽象

(对照项为框架取向的概括,具体以各兄弟子库 doc 为准。)

4.8 代码地图(导航索引)

主题文件路径(相对克隆根 lib/crewai/src/crewai/)符号名
Agent 干活入口agent/core.pyAgent.execute_task / Agent._execute_without_timeout
ReAct 循环agents/crew_agent_executor.pyCrewAgentExecutor._invoke_loop_react
原生工具循环agents/crew_agent_executor.py_invoke_loop_native_tools / _handle_native_tool_calls
输出解析agents/parser.pyparse / AgentAction / AgentFinish / _safe_repair_json
新默认执行器(Flow 子类)experimental/agent_executor.pyAgentExecutor
Crew 入口crew.pyCrew.kickoff
任务编排循环crew.pyCrew._execute_tasks
层级经理创建crew.pyCrew._create_manager_agent
工具装配crew.pyCrew._prepare_tools / _add_delegation_tools
委派/提问工具tools/agent_tools/agent_tools.pyAgentTools.tools / DelegateWorkTool / AskQuestionTool
任务执行核心task.pyTask._execute_core / Task.execute_sync
流程枚举process.pyProcess
Flow 公共类flow/flow.pyFlow
Flow 引擎flow/runtime/__init__.pyFlow.kickoff / kickoff_async / _execute_listeners
Flow 元类/状态flow/runtime/__init__.pyFlowMeta / FlowState
装饰器 DSLflow/dsl/_listen.py _router.py _start.py _conditions.pylisten / router / start / or_ / and_
LLM 抽象llm.py / llms/base_llm.pyLLM / _ensure_litellm / BaseLLM
提示词组装utilities/prompts.pyPrompts.task_execution
统一记忆memory/unified_memory.pyMemory.remember / Memory.recall
事件总线events/event_bus.pyCrewAIEventsBus (crewai_event_bus)