☰
forgecode Followup 工具深度解析:AI 结对编程中的澄清追问与多选交互机制
2026/9/28 13:03:08 网站建设 项目流程
  • 人工智能
  • AI Agent
  • 代码智能体
  • AI 应用
  • CLI
  • 开发工具

【免费下载链接】forgecode

AI enabled pair programmer for Claude, GPT, O Series, Grok, Deepseek, Gemini and 300+ models

项目地址:https://gitcode.com/gh_mirrors/forge39/forgecode
点击查看免费下载

本文以 forgecode 仓库中 followup.md 的定义为核心,系统讲解 Followup(追问)工具的设计意图、输入协议、三种交互模式、底层实现与结果回流机制。读完本文,你将掌握该工具在 Agent 工作流中的完整调用链路,理解如何利用它在信息不充分时向用户发起单选项、多选项或自由文本澄清,从而写出更精准、更低往返成本的 Agent 提示与工具调用。

Followup 工具是什么

在 AI 结对编程场景中,模型面对模糊需求或缺少关键信息时,与其猜测并执行错误操作,不如主动向用户提问。forgecode 的 Followup 工具正是为此设计的专用通道,其官方描述原文如下:

Use this tool when you encounter ambiguities, need clarification, or require more details to proceed effectively. Use this tool judiciously to maintain a balance between gathering necessary information and avoiding excessive back-and-forth.

这段描述传达了两个核心设计原则:

  1. 适用场景明确:当遇到歧义(ambiguities)、需要澄清(clarification)或需要更多细节(more details)以继续有效工作时才调用它,即“信息不足,先问再动”。
  2. 强调克制使用(judiciously):追问本身会产生一次额外的用户交互往返(back-and-forth),因此要平衡“收集必要信息”与“避免过多往返”之间的关系,能基于上下文合理推断的问题不必反复追问。

该描述通过#[tool_description_file = "crates/forge_domain/src/tools/descriptions/followup.md"]宏挂载到Followup输入结构体上(见 catalog.rs),会随工具定义一起注入模型上下文,成为模型决定“何时该问、怎么问”的行为依据。

输入协议:question、multiple 与 option1~option5

Followup 工具的输入由Followup结构体定义(catalog.rs),字段如下:

字段类型是否必填说明
questionString必填要向用户提出的问题
multipleOption<bool>可选为true时允许多选;为false(默认)时只能单选
option1Option<String>可选候选选项 1
option2Option<String>可选候选选项 2
option3Option<String>可选候选选项 3
option4Option<String>可选候选选项 4
option5Option<String>可选候选选项 5

从实现细节看:question是唯一必填字段;multiple与五个选项均标注#[serde(skip_serializing_if = "Option::is_none")],未提供时不会出现在序列化 JSON 中,保持传输负载精简。

一个典型的单选调用示例如下:

{ "question": "Which file would you like to edit?", "option1": "src/main.rs", "option2": "src/lib.rs", "option3": "tests/integration.rs" }

一个典型的多选调用示例如下:

{ "question": "Which modules should be covered by the new tests?", "multiple": true, "option1": "auth", "option2": "billing", "option3": "notifications" }

三种交互模式的决策逻辑

Followup提交后,参数会先经 tool_executor.rs 汇聚:option1~option5通过chain依次收集为Vec<String>,连同question、multiple一起交给FollowUpService::follow_up服务。真正的交互决策在 followup.rs 中完成,逻辑可概括为:

match (options.is_empty(), multiple.unwrap_or_default()) { (true, _) => 自由文本输入(prompt_question) (false, true) => 多选(select_many) (false, false)=> 单选(select_one) }

三种模式的行为与结果格式:

  • 无选项(自由输入):options为空时,无论multiple取何值,都会弹出自由文本输入框,让用户直接键入回答,返回用户输入的原文。
  • 单选:提供选项且multiple为false(或未提供)时,弹出单选菜单,返回User selected: {selected}格式的字符串。
  • 多选:提供选项且multiple为true时,弹出多选菜单,返回User selected N option(s): {option_a}, {option_b}格式的字符串(N 为用户实际勾选的数量)。

需要特别注意的是:当options为空时multiple参数不产生任何作用(对应(true, _)分支),这也是结构体注释中“默认单选、多选需显式开启”这一约定在服务端的落地。

底层 UI 实现:ForgeWidget 与阻塞线程调度

交互式追问的界面层位于 forge_infra/src/inquire.rs,通过ForgeInquire实现UserInfratrait 的三个方法:

  • prompt_question:调用ForgeWidget::input(&question).allow_empty(true)渲染自由文本输入框,并允许空输入;
  • select_one:调用ForgeWidget::select(&message, options)渲染单选列表,选项为空时直接返回None;
  • select_many:调用ForgeWidget::multi_select(&message, options)渲染多选列表,同样在选项为空时返回None。

这些交互都通过spawn_blocking在阻塞线程池中执行(ForgeInquire内部将闭包交给tokio::task::spawn_blocking),避免 TUI 的同步阻塞操作拖垮异步事件循环。此外,select_one/select_many在options为空时会提前返回Ok(None),与服务层(true, _)分支互为兜底,保证任何路径都不会因空选项而出错。

ForgeInquire在 forge_infra.rs 中作为基础设施(infra)被实例化为Arc<ForgeInquire>,再注入ForgeFollowup服务,形成App → Service → Infra → Widget的分层调用链。

结果如何回流给模型:feedback 与 interrupted 语义

追问结果最终要转成模型可读的工具输出。在 operation.rs 中,ToolOperation::FollowUp { output }有两种渲染分支:

  • output为Some(content):渲染为 XML 元素<feedback>用户的选择或回答</feedback>,表示用户已给出有效反馈;
  • output为None:渲染为<interrupted>No feedback provided</interrupted>,表示用户中断或未提供反馈。

这两种语义对模型至关重要:<feedback>意味着拿到了下一步行动依据,可以继续推进;<interrupted>则提示模型本次追问没有得到有效答复,需要调整策略(例如改用其他工具或降低追问频率)。

对应的快照测试覆盖了这两种形态:follow_up_with_question.snap 与 follow_up_no_question.snap;单元测试test_follow_up_with_question/test_follow_up_no_question位于 operation.rs。格式化与回放侧同样有对应测试(见 fmt_output.rs 的test_follow_up_with_response与test_follow_up_no_response),保证对话记录在不同渲染阶段的一致性。

在 Agent 工作流中的位置与上下文保持

Followup 的注册与排序位于 catalog.rs:ToolCatalog::Followup(Followup)是工具枚举成员之一,并在工具顺序列表中占据一席([ToolKind::Followup]),模型可随工具清单随时调起。它是一类典型的“人机交互”工具,不触碰文件系统、不执行命令,只在模型与用户之间传递澄清信息。

在上下文压缩(compaction)场景中,Followup 调用还会被折叠进摘要。相关证据包括:

  • summary.rs 定义了SummaryTool::Followup { question: String },并提供工厂方法tool_call_followup(question)生成默认值的 Followup 摘要调用;
  • trim_context_summary.rs 会将摘要中的SummaryTool::Followup重新映射为Operation::Followup,保持压缩前后语义一致;
  • strip_working_dir.rs 在剥离工作目录信息时同样保留SummaryTool::Followup条目。

这意味着即便长会话触发压缩,模型仍能在摘要中看到“曾向用户追问过什么问题”,从而在恢复上下文后继续围绕未决问题工作。

最佳实践:何时问、怎么问

结合工具描述与服务实现,使用 Followup 时建议遵循以下原则:

  1. 问前先穷尽上下文:优先通过fs_read、fs_search、semantic_search等工具在仓库中自行寻找答案;只有信息确实不足时再发起追问,呼应“judiciously”的设计要求。
  2. 问题必须具体:question是唯一必填项,提问质量直接决定回答质量,避免“你想怎么做?”这类开放问题,尽量给出可执行的候选范围。
  3. 能用选项就不用自由输入:提供option1~option5候选选项可把用户操作成本降到最低(一次回车即完成),而自由输入需要用户手动键入。当选项不明确时才退回自由文本模式。
  4. 区分单选与多选:只需一个答案时保持multiple缺省或为false;确实需要同时获得多个选择(例如“哪些模块需要测试”)时才置true,避免单选迫使模型后续再追问一次。
  5. 接受“无反馈”结果:用户可能直接中断(<interrupted>),模型应将其视为未获得反馈的正常分支,而不是错误,并据此调整后续行动。

相关源码导航

  • 工具描述原文:crates/forge_domain/src/tools/descriptions/followup.md
  • 输入结构体与工具注册:crates/forge_domain/src/tools/catalog.rs
  • 服务层三种交互模式:crates/forge_services/src/tool_services/followup.rs
  • 服务 trait 定义:crates/forge_app/src/services.rs
  • 执行器调用链(选项汇聚):crates/forge_app/src/tool_executor.rs
  • UI 基础设施(input/select/multi_select):crates/forge_infra/src/inquire.rs
  • 结果 XML 渲染与快照测试:crates/forge_app/src/operation.rs
  • 压缩摘要中的 Followup 保持:crates/forge_domain/src/compact/summary.rs

以上链路完整覆盖了“描述定义 → 参数解析 → 服务决策 → UI 交互 → 结果回流 → 上下文压缩”的全过程,是理解 forgecode 人机协作机制的重要入口。

  • 人工智能
  • AI Agent
  • 代码智能体
  • AI 应用
  • CLI
  • 开发工具

【免费下载链接】forgecode

AI enabled pair programmer for Claude, GPT, O Series, Grok, Deepseek, Gemini and 300+ models

项目地址:https://gitcode.com/gh_mirrors/forge39/forgecode
点击查看免费下载

相关推荐

上一篇:【亲测免费】 探索Jikan:一款高效、易用的MyAnimeList API
下一篇:如何第一次运行ADHD?用Claude Code的/adhd命令设计限流器完整实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询