跳到主要内容

让平台成为 Agent 的 LLM 节点:对话、工具调用循环、规划 Agent

30 秒导读: 前几章讲的是"一张图怎么被跑起来"(见 03-workflow-engine.md)。这一章讲图里那几个真正接大模型的节点:从"调一次模型就返回"的对话节点,到"模型自己决定调工具、看结果、再决定"的工具循环节点,再到"会先列计划、卡住了会反问用户"的规划 Agent。正是这几个节点,把 FastGPT 从"可视化工作流"升级成"Agent 平台"。


1. 这是什么(零基础也能懂)

一句话定义: 本章讲的是工作流里把大语言模型接进来的那几种节点——它们的区别不在"调哪个模型",而在"给模型多大的自主权"。

先建立最重要的一个直觉:自主权是逐级放开的

节点模型的自主权一句话
基础对话节点无。调一次,出答案你问,它答
工具调用节点中。可反复自己挑工具你给它工具,它自己边想边用
规划 Agent 节点高。会先列计划、卡住会反问你给它目标,它自己拆步骤、追问、执行到完成
辅助 LLM 节点极小。做一件固定小事分类 / 抽字段 / 扩写问题

给谁用: 搭工作流的人。想做个"知识库问答机器人",用对话节点就够;想做个"能查资料、能算数、能调外部 API 的助手",用工具调用节点;想做个"给个复杂任务能自己规划着干完"的 Agent,用规划 Agent 节点

一句话直觉/类比:

基础对话 = 一次性问答:模型是"应答机"
工具循环 = 模型手里多了一串遥控器(工具),它按需一个个按,看反馈再按下一个
规划 Agent = 工具循环 + 一块随身白板(plan):先在白板上写下步骤,
干一步勾一步,缺料就举手问你(ask),全部勾完才收工

本章不重复的部分: 节点怎么被调度器选中并喂进参数,已在 03-workflow-engine.md 讲过;知识库检索节点内部(向量化、混合检索)归 05-knowledge-base.md。本章只钻这几个节点自己的算法与多轮控制


2. 顶层全景(它大概怎么转)

2.1 三层节点,一个共用内核

最关键的架构事实:工具循环节点和规划 Agent 节点,底下是同一个 while 循环 runAgentLoop。对话节点则不进这个循环,只调一次。

一次对话请求

┌─────────────┼──────────────────────┐
▼ ▼ ▼
① 基础对话节点 ② 工具调用节点 ③ 规划 Agent 节点
dispatchChat dispatchRunTools dispatchRunAgent
Completion │ │
│ ▼ ▼
│ runToolCall runUnifiedAgentLoop
│ (toolCall.ts) (unified.ts:叠加 plan/ask/stop-gate)
│ │ │
│ └───────────┬───────────┘
▼ ▼
createLLMResponse runAgentLoop ← 共用的多轮工具循环内核
(调一次模型) (loop/base.ts:while 里反复调模型 + 执行工具)

怎么读这张图:从左到右自主权递增。①走一条直线;②③都汇入 runAgentLoop 这个 while 循环,区别只在③在循环外面多包了一层 plan/ask/stop-gate 的编排(runUnifiedAgentLoop)。

2.2 各部件一句话职责

部件干什么在哪个文件
dispatchChatCompletion基础对话:组 prompt、拼知识库引用、流式返回dispatch/ai/chat.ts:59
dispatchRunTools工具节点入口:备料、算钱、拼 assistantResponsesdispatch/ai/toolcall/index.ts:21
runToolCall工具节点主编排:把职责拆成 hook,调 runAgentLoopdispatch/ai/toolcall/toolCall.ts:34
runAgentLoop多轮工具循环内核:压缩→调模型→跑工具→判停ai/llm/agentLoop/loop/base.ts:186
dispatchRunAgent规划 Agent 入口:备工具/文件/沙箱/memorydispatch/ai/agent/index.ts:113
runUnifiedAgentLoop单主 Agent 循环:在内核外叠 plan/ask/stop-gateai/llm/agentLoop/loop/unified.ts:134
辅助节点分类 / 抽字段 / 问题扩写,各调一次模型classifyQuestion.tsextract.tsfunctions/queryExtension.ts

3. 核心原理(逐个机制,由浅入深)

3.1 基础对话节点 dispatchChatCompletion

它要解决的小问题: 把"用户这句话 + 历史 + 知识库引用 + 系统提示"拼成一份合法的 messages,调一次模型,把答案流式吐回前端。

思路: 全程只有一次模型调用,没有循环。难点全在调用之前的 prompt 组装调用期间的流式转发

① 知识库引用怎么塞进去(user 还是 system?)。 getDatasetCiteData 决定引用文本放进 user 消息还是 system 消息:

  • aiChatQuoteRole === 'user',或引用模板里含 {{question}} 占位符 → 引用拼进 user 输入
  • 否则 → 引用拼进 system 提示
// 示意,非源码:引用角色的判定
const quoteRole =
aiChatQuoteRole === 'user' || datasetQuotePrompt.includes('{{question}}')
? 'user'
: 'system';

真实实现见 chat.ts:345 getDatasetCiteDataquoteRole 的计算;引用文本由 replaceVariable{{quote}}/{{question}} 填进模板。

② 系统提示怎么拼。 getChatMessages 把三段用固定分隔符串起来——模型自带的默认系统提示、用户填的系统提示、知识库引用系统提示:

// 示意,非源码:三段系统提示拼接
const concatenateSystemPrompt = [
model.defaultSystemChatPrompt,
systemPrompt,
datasetCiteSystemPrompt
].filter(Boolean).join('\n\n===---===---===\n\n');

真实实现 chat.ts:410 concatenateSystemPrompt。随后 filterGPTMessageByMaxContextchat.ts:469)按 maxContext - maxTokens旧到新裁历史,保证不超窗。

③ 流式转发。 调用 createLLMResponse 时挂了两个回调,把模型吐出的 reasoning / answer 增量实时推给前端 SSE:

  • onReasoningchat.ts:213)→ 推 reasoning_content
  • onStreamingchat.ts:222)→ 推 text

两者都受开关控制(aiChatReasoningisResponseAnswerText)。

④ 收尾。 算钱(formatModelChars2Points chat.ts:238,用户自带 key 则计 0 分),把 OpenAI 格式的 completeMessages 转回 FastGPT 的对话结构(GPTMessages2Chats chat.ts:254),作为 history 输出。

关键点: 对话节点没有"再问一次模型"的能力。它把 answerText 同时挂到 toolResponsechat.ts:297),所以它也能被当作工具节点的一个子工具来调——但它自己内部不会循环。


3.2 工具调用 Agent 循环:多轮 while 是怎么转的

这是本章的核心。工具节点让模型自己决定调哪个工具,执行完把结果回填,再问模型,直到模型不再要工具为止。

3.2.1 入口备料:dispatchRunTools

dispatchRunToolstoolcall/index.ts:21)负责循环开始前的准备:

  1. 按模型能力位与用户开关,收敛 vision/audio/video/reasoning(index.ts:71);
  2. useToolNodeListindex.ts:79)从图里收集"连在本节点下面的工具节点";
  3. 把自己的入口标记清掉props.node.isEntry = falseindex.ts:86)——本轮之后由子工具接管交互恢复入口;
  4. useToolMessagesindex.ts:88)拼 messages,并把用户上传文件的 URL 换成模型可 read_file 的文件 id;
  5. runToolCall,注意消息适配时 reserveTool: trueindex.ts:126),保留历史里的工具调用结构。

3.2.2 主编排:runToolCall 把职责拆成 hook

runToolCalltoolCall.ts:34)本身只做编排,把重活分给几个 hook——这样 toolCall.ts 只保留主流程:

Hook职责
useToolCatalog把工具节点整理成 OpenAI tools 描述 + 反查表
useToolNodeResponse收集/落库每个工具子流程的运行详情
useToolStreamResponse把 reasoning/answer/工具调用/工具结果推给前端
useToolRunner真正执行一个工具(跑子工作流 / sandbox / 读文件)

然后它调共用内核 runAgentLoop,关键参数:

  • maxRunAgentTimes: 50toolCall.ts:130)——最多 50 轮;
  • canBatchTool: () => falsetoolCall.ts:161)——工具串行执行(因为工具子流程依赖流式顺序和交互状态);
  • onRunTool: runTooltoolCall.ts:200)——把"执行工具"的实现注入内核。

3.2.3 内核 while 循环:runAgentLoop

runAgentLoopbase.ts:186)是②③共用的心脏。一轮 while(base.ts:316)做四件事:

while (runTimes < maxRunAgentTimes) {
1. 压缩上下文 onCompressContext:超长才压,压完记 checkpoint
2. 调模型 createLLMResponse:拿 answer / reasoning / toolCalls
3. 若有工具调用 逐个/批量 runTool → 结果作为 tool 消息 append 回 messages
4. 判停 无工具调用?→ 问 onStopCandidate 能不能停;能停就 break
}

第 2 步的防死循环细节: 若模型连续多轮只调工具不给答案,consecutiveRequestToolTimes 累加(base.ts:428);一旦超过 5,下一轮强制 tool_choice: 'none'base.ts:383)逼它给最终答案。有答案时该计数清零(base.ts:431)。

第 3 步的并行控制: 内核支持工具并行(batchRunbase.ts:621),但通过 canBatchTool 逐个判断——返回 false 的工具串行跑(base.ts:601)。工具节点全串行;Agent 节点则对普通工具放开并行(见 3.5)。

第 3 步的结果回填: 每个工具结果按 toolCalls 原始顺序写回成 tool 消息(base.ts:562),保证后续模型看到的上下文稳定;工具响应默认还会过一遍 compressToolResponse 压缩(base.ts:514)。

真实实现引用:

// base.ts:669 循环结束条件(四选一即停)
if (toolCalls.length === 0 || !!interactiveResponse || stopAgentLoop || isAborted?.()) {
break;
}

即:模型不再要工具、命中交互工具、被特殊停止工具叫停、或用户主动中止。

3.2.4 stopTool:一个"只发信号"的工具

工作流里可以放一个"停止工具调用"节点。它的 dispatch 什么都不干,只在 nodeResponse 里插一个标记:

// toolcall/stopTool.ts:10 dispatchStopToolCall
return {
[DispatchNodeResponseKeyEnum.nodeResponse]: {
toolStop: true // 只发信号,不算执行错误
}
};

信号怎么被内核听见?链路是:toolStop → 子流程摘要的 hasToolStopuseToolRunnerstop: toolRuntimeSummary.hasToolStopuseToolRunner.ts:214)→ 内核里 stopLoopstopAgentLoop = truebase.ts:583)→ 下一次判停 break。它让"模型说完这句就收工"变成工作流可编排的一步。

3.2.5 计费累积与 assistantResponses 组装

计费——为什么要"每次调用单独计价再累加"? 因为模型可能是梯度计费(用量越大单价不同)。若把多轮 token 求和后一次性算钱会算错。所以内核每轮单独 formatModelChars2Points 后累加 llmTotalPointsbase.ts:437)。这个值一路传成 toolCallTotalPointstoolCall.ts:221),最后 dispatchRunTools 里再加上工具本身的花费:

// toolcall/index.ts:154
const totalPointsUsage = modelTotalPoints + toolTotalPoints;

assistantResponses——落库给谁看? 循环里模型产生的所有 assistant 消息(含工具调用轮)由 GPTMessages2ChatstoolCall.ts:204reserveTool: true)转回 FastGPT 的结构化对话值 AIChatItemValueItemType[],这就是持久化进 assistant.value、前端渲染成"思考+工具卡+回答"的东西。出库前再过 filterToolResponseToPreviewindex.ts:155)把工具长响应裁成预览。


3.3 规划 Agent:dispatchRunAgent + runUnifiedAgentLoop

规划 Agent 在工具循环之上,多了两样东西:plan(随身白板)ask(举手提问)

3.3.1 入口 dispatchRunAgent 备了什么料

dispatchRunAgentagent/index.ts:113)比工具节点多备三样:

  1. 引擎分支AGENT_ENGINE === 'pi' 时走 dispatchPiAgent,默认走 unified loop(index.ts:115);
  2. 子应用/工具汇总getSubappsindex.ts:253)把用户选的工具、系统工具、知识库/文件工具、sandbox 工具合成两份——completionTools(给模型看的描述)和 subAppsMap(执行时反查真实实现);
  3. memory 恢复readWorkflowAgentLoopMemoryindex.ts:330)读回上一轮 ask 暂停时存下的上下文。

然后创建一个"工作流适配器" runtime(index.ts:309),把工具执行、SSE、计费、nodeResponse 全做成回调传进去——通用 agent loop 不感知 workflow,全靠这些回调把两边接起来。

3.3.2 单主循环 runUnifiedAgentLoop

runUnifiedAgentLoopunified.ts:134不自己写 while,而是复用 3.2.3 的 runAgentLoop,只是往里注入了三类"内部工具"的处理。它给模型的工具集是(tools/index.ts:35 getToolsForUnifiedLoop):

runtimeTools(业务工具) + ask_agent(追问) + update_plan(维护计划)

normalizeToolCatalogtools/index.ts:18)会剔除跟内部工具重名的业务工具,防止模型把控制工具当业务工具用。

onRunToolunified.ts:279)里按工具名分三条路:

模型调的工具处理
ask_agent解析追问载荷,存进 pendingAsk,返回 stop: true 暂停循环(unified.ts:299
update_planapplyPlanUpdate 改白板状态,置 runtimeToolCalledSinceLastPlanUpdate = falseunified.ts:305
其它(业务工具)runtimeToolCalledSinceLastPlanUpdate = true,交 runtime 真跑(unified.ts:325

3.3.3 交互式规划:plan 与 stop gate

为什么需要 stop gate(停止门)? 因为模型可能"计划没干完就想收工"。stop gate 是一道本地兜底闸:每当模型这一轮不再调工具、准备给最终答案,内核就回调 onStopCandidatebase.ts:641)问 unified loop "能停吗",后者调 runStopGateunified.ts:344stop/index.ts:25)检查白板。

runStopGate 的判定(stop/index.ts:25):

  • 有步骤没到 done/skipped/blocked,或 blocked 却没写 blocker,或标了 needsReplan不许停
  • 用了业务工具但还没 update_plan 记录结果 → 不许停
  • 用户明确要"计划模式"却还没建 plan → 不许停

不许停时,它不抛错,而是造一条 <stop_gate_feedback> 用户消息塞回同一个循环base.ts:663continue),让模型自己接着干。被打回的那次 assistant 输出会从可持久化结果里 pop 掉(base.ts:661),只当上下文。最多打回 maxStopGateRejections(默认 2)次,超了才真报错(unified.ts:356)。

反向的一面 forceFinalAnswerOnly 计划一旦满足 stop gate,getRequestControlunified.ts:213)把下一轮 tool_choice 设为 'none'——计划干完了就只准出答案,不许再挑工具

"用户明确要计划"怎么识别? shouldRequirePlanFromMessagesplan/requirePlan.ts:32)用一组正则匹配最后一条用户消息,命中"计划模式 / 创建计划 / 每步更新计划"等(requirePlan.ts:3EXPLICIT_PLAN_PATTERNS)就强制 requirePlan = true。注意注释点破:这不是复杂度判断,是 UI/状态契约——用户要了计划,哪怕模型觉得能直接答也得先建 plan。

update_plan 的状态机plan/state.ts:257 applyPlanUpdate)接受一个 updates 数组,支持三种 operation:set_plan(建整份)、update_step(改单步,state.ts:84)、replace_plan(换计划并保留稳定的已完成步骤)。批量里任一步失败则整批回滚、不落任何改动state.ts:286)。

3.3.4 ask:暂停、planId、恢复同一份 messages

这是规划 Agent 最巧的一环——追问用户后,怎么在用户回答后接着原来的思路跑,而不是重开一份上下文。

追问工具 ask_agentplan/askTool.ts:16)要求模型给出 question + 3~5 个可直接点选的 optionsaskTool.ts:4PlanAskPayloadSchema),且只在三种硬阻塞时才准用:缺必需私有输入、必需工具不可用、目标完全不明。

暂停与恢复的时序:

第 1 轮(用户提问)
模型调 ask_agent
→ unified.ts:299 存 pendingAsk(含当时完整 messages 快照)
→ 循环 stop
→ dispatch 层转成 interactive 卡片给前端(agent/index.ts:349 status==='ask')
→ 把 pendingMainContext 写进节点 memory(index.ts:375)
→ 给这次追问打上 planId(index.ts:358)

〔前端展示选项,等用户点〕

第 2 轮(用户回答)
→ readWorkflowAgentLoopMemory 读回 pendingMainContext(index.ts:330)
→ userAnswer = 用户这次的输入(index.ts:342)
→ runUnifiedAgentLoop 把用户答案作为"那个 ask 工具的 Tool 响应"
append 回上次的 messages 快照,延续同一条链(unified.ts:177)

关键代码(unified.ts:177):

// 示意,非源码:恢复时不是重开,而是把用户答案补成 ask 工具的响应
const messages =
input.pendingMainContext && input.userAnswer !== undefined
? [
...input.pendingMainContext.messages, // 上次中断时的完整消息链
{ role: 'tool',
tool_call_id: input.pendingMainContext.askToolCallId, // 对准那次 ask
content: normalizeToolResponseContent(input.userAnswer) }
]
: buildInitialMessages({ input, hasRuntimeTools });

planId 的作用(agent/index.ts:357 起注释点破):保存时把它回写到用户答案上,下一轮 chats2GPTMessages 据此跳过那条 UI-only 的追问气泡,既保证上下文连续,又保证缓存命中。

3.3.5 sub agent:Agent 手里的六类"手脚"

规划 Agent 能调的工具,落地成 dispatch/ai/agent/sub/ 下六类 sub agent。它们各自是一段独立的执行逻辑,被 runtime 的 executeTool 按工具名分发:

sub agent干什么入口
app把另一个 App / 插件当工具跑(子工作流)sub/app/index.ts:57 dispatchApp / :156 dispatchPlugin
dataset知识库检索工具,检索后可再用 LLM 自动筛相关分块sub/dataset/index.ts:165 dispatchAgentDatasetSearch
file读取用户上传文件内容sub/file/index.ts:16 dispatchFileRead
model轻量单次模型子任务(不进循环,调一次就返回)sub/model/index.ts:35 dispatchModelAgent
sandbox代码沙箱工具适配(真执行在 sandbox 接口层)sub/sandbox/tool.ts:16 dispatchSandboxTool
tool系统/用户配置的普通工具sub/tool/index.ts:57 dispatchTool

dispatchModelAgentmodel/index.ts:35)的注释点破了它和主循环的区别:"不参与 agent loop,只负责按给定 systemPrompt/task 调一次 LLM 并返回文本和 usage"——它是给 Agent 用的"叫个小模型干件杂事"的能力,不是又一层循环。dataset sub agent 检索完还会用 selectRelevantChunksByLLM 让模型再挑一遍最相关分块(检索本身归 05-knowledge-base.md)。


4. 辅助 LLM 节点(各做一件固定小事)

这三类节点也调模型,但没有循环、没有工具,只把模型当成一个"结构化函数"。

① classifyQuestion(问题分类 / 路由)。 dispatchClassifyQuestionclassifyQuestion.ts:38)给模型一份类目列表和用户输入,让它吐出命中的类目 key,命中不了就落到最后一个兜底类目(classifyQuestion.ts:66)。它的输出是跳过哪些分支句柄skipHandleIdclassifyQuestion.ts:87)——即用分类结果控制图往哪条边走。它还把上次分类结果写进 memory(classifyQuestion.ts:90)供多轮参考。

② contextExtract(字段抽取)。 dispatchContentExtractextract.ts:43)给模型一份 JSON schema,让它从文本里抽字段。拿到回答后 sliceJsonStr 切出 JSON 段(extract.ts:214)、json5.parse 容错解析(extract.ts:246),再校验必填字段是否齐全给出 success。解析失败不报错,返回空对象兜底(extract.ts:236)。

③ queryExtension(问题扩写)。 queryExtensionfunctions/queryExtension.ts:108)把一句原始问题扩写成多条检索问题(默认 10 条,queryExtension.ts:116),喂给知识库检索以提召回率。它把历史组成 few-shot 拼进 prompt(queryExtension.ts:147),是典型的"一次调用、结构化输出"。

共同模式: 三者都直接调 createLLMResponse(不走 runAgentLoop),都用 getWorkflowSourceNodeKey 存/取 memory,都在末尾 usagePush 计费。它们是"把 LLM 当纯函数",与前面"把 LLM 当自主 Agent"形成对照。


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

  1. 一个内核,两种自主权。 工具节点和规划 Agent 共用 runAgentLoopbase.ts:186),差异全靠"往内核注入不同回调"表达——onRunToolonStopCandidategetRequestControlcanBatchTool。加一层能力不用改内核,只加编排。

  2. stop gate 用 feedback 消息而非异常来"不放行"。 计划没干完时,把一条合成用户消息塞回同一循环 continuebase.ts:663),模型在原上下文里自我纠偏,避免了"外层重开一层循环"的复杂度和上下文丢失。

  3. ask 恢复是"补一条工具响应",不是重建上下文。 用户答案被当作那次 ask_agent 的 Tool 响应 append 回消息快照(unified.ts:177),配合 planId 跳过 UI 气泡(agent/index.ts:357),把"人机多轮追问"无缝缝进"模型工具循环"里。

  4. 梯度计费的正确姿势:每轮单独计价再累加。 llmTotalPoints += totalPointsbase.ts:437)而非"总 token 一次算",避免阶梯定价下的系统性算错。

  5. 连续工具调用的防死循环。 超过 5 轮只调工具不出答案就强制 tool_choice: 'none'base.ts:383),给自嗨的模型一个硬刹车。


6. 边界与局限

  • 对话节点不会循环。 dispatchChatCompletion 只调一次模型;要多轮工具就得用工具节点。它虽把答案挂进 toolResponsechat.ts:297)可被当子工具调,但自身无自主权。
  • 工具节点内工具串行。 runToolCallcanBatchTool: () => falsetoolCall.ts:161),因为子工具依赖流式顺序与交互状态;需要并行只有规划 Agent 的普通工具路径才放开。
  • ask 只允许硬阻塞。 prompt(prompt/mainPrompt.ts:57<ask_rules>)和 schema 都限定:只有缺必需私有输入 / 工具不可用 / 目标完全不明才准追问,偏好和可假设的信息不许问。
  • unified loop 暂不支持交互工具。 onRunInteractiveTool 直接返回 "not supported yet"(unified.ts:342)——规划 Agent 里的工具不能再触发子级交互式中断。
  • stop gate 最多打回 2 次。 超过 maxStopGateRejectionsunified.ts:356)就以"计划未完成"报错收场,防止无限自我纠偏。
  • planId 依赖 memory 落库。 ask 恢复靠节点 memory(agent/index.ts:330/375);memory 丢失则无法接回原上下文。

7. 横向对比(与本组其它章)

想了解去哪章
节点/边/引用/变量的数据模型01-workflow-data-model.md
一次对话从 API 到 SSE 返回的端到端路径02-chat-pipeline.md
调度器怎么把整张图跑起来、怎么调用本章节点03-workflow-engine.md
本章(LLM 节点内部的算法与多轮控制)你在这里
知识库检索节点内部(向量化、混合检索、重排)05-knowledge-base.md

8. 代码地图(导航索引)

主题文件路径符号名
基础对话节点packages/service/core/workflow/dispatch/ai/chat.tsdispatchChatCompletion
知识库引用角色判定packages/service/core/workflow/dispatch/ai/chat.tsgetDatasetCiteData
系统提示拼接 + 裁窗packages/service/core/workflow/dispatch/ai/chat.tsgetChatMessages
工具节点入口packages/service/core/workflow/dispatch/ai/toolcall/index.tsdispatchRunTools
工具节点主编排packages/service/core/workflow/dispatch/ai/toolcall/toolCall.tsrunToolCall
工具执行实现packages/service/core/workflow/dispatch/ai/toolcall/hooks/useToolRunner.tsuseToolRunner
停止信号工具packages/service/core/workflow/dispatch/ai/toolcall/stopTool.tsdispatchStopToolCall
多轮工具循环内核packages/service/core/ai/llm/agentLoop/loop/base.tsrunAgentLoop
规划 Agent 入口packages/service/core/workflow/dispatch/ai/agent/index.tsdispatchRunAgent
单主 Agent 循环packages/service/core/ai/llm/agentLoop/loop/unified.tsrunUnifiedAgentLoop
stop gate 判停packages/service/core/ai/llm/agentLoop/stop/index.tsrunStopGate
plan 状态机packages/service/core/ai/llm/agentLoop/plan/state.tsapplyPlanUpdate
强制计划识别packages/service/core/ai/llm/agentLoop/plan/requirePlan.tsshouldRequirePlanFromMessages
追问工具packages/service/core/ai/llm/agentLoop/plan/askTool.tscreateAskAgentTool
Main Agent 系统提示packages/service/core/ai/llm/agentLoop/prompt/mainPrompt.tsgetMainAgentSystemPrompt
工具可见性packages/service/core/ai/llm/agentLoop/tools/index.tsgetToolsForUnifiedLoop
sub agent · app/插件packages/service/core/workflow/dispatch/ai/agent/sub/app/index.tsdispatchApp / dispatchPlugin
sub agent · 知识库packages/service/core/workflow/dispatch/ai/agent/sub/dataset/index.tsdispatchAgentDatasetSearch
sub agent · 读文件packages/service/core/workflow/dispatch/ai/agent/sub/file/index.tsdispatchFileRead
sub agent · 单次模型packages/service/core/workflow/dispatch/ai/agent/sub/model/index.tsdispatchModelAgent
辅助节点 · 分类路由packages/service/core/workflow/dispatch/ai/classifyQuestion.tsdispatchClassifyQuestion
辅助节点 · 字段抽取packages/service/core/workflow/dispatch/ai/extract.tsdispatchContentExtract
辅助节点 · 问题扩写packages/service/core/ai/functions/queryExtension.tsqueryExtension