- AI 应用
- 代码智能体
- 交互助手
- CLI
- MCP Clients
- 人工智能
【免费下载链接】crush
Glamourous agentic coding for all 💘
导读
Crush 是一个面向终端场景的 Glamourous agentic coding 工具,为编码代理内置了一套完整的网页内容获取工具族。其中agentic_fetch是一个特殊的工具:它不是简单抓取网页原文,而是启动一个独立的 AI 子代理,借助web_search与web_fetch等工具完成搜索、抓取、提炼、摘要与问答,把"取回内容"和"理解内容"两步合一。读完本文,你将理解agentic_fetch与普通fetch的定位差异、它的两种工作模式(指定 URL 模式与自由搜索模式)、底层子代理的模型与工具构成、权限与会话机制,以及它在什么场景下值得付出更高的延迟与成本。
一、工具定位:一行描述背后的设计意图
agentic_fetch的工具描述位于 internal/agent/templates/agentic_fetch.md,全文即其对外暴露的能力声明:
Fetch a URL or search the web using an AI sub-agent that can extract, summarize, and answer questions. Slower and costlier than fetch; use fetch for raw content or API responses.
(通过 AI 子代理抓取 URL 或搜索网络,用于提取信息、生成摘要和回答问题。相比fetch更慢、更贵;如需原始内容或 API 响应,请使用fetch。)
这段描述点明了三个核心事实:
- 它是子代理(sub-agent)驱动的:调用一次
agentic_fetch,Crush 会启动一个全新的、独立的会话代理来执行任务,而不是在主代理上下文中直接抓取。 - 它不止于抓取:输出的是"提取、摘要、问答"的结果,而非页面原文。
- 它与
fetch形成明确分工:追求原始内容、接口响应时用轻量的fetch;需要理解与加工内容时用昂贵的agentic_fetch。
在 internal/agent/coordinator.go#L815-L821 中可以看到,该工具与agent工具一样,只有在代理配置的AllowedTools列表里显式包含agentic_fetch时才会被注册进工具集:
if slices.Contains(agent.AllowedTools, tools.AgenticFetchToolName) { agenticFetchTool, err := c.agenticFetchTool(ctx, nil) if err != nil { return nil, err } allTools = append(allTools, agenticFetchTool) }工具名常量定义在 internal/agent/tools/fetch_types.go:
const AgenticFetchToolName = "agentic_fetch"二、fetch 工具族全景:在什么位置选择 agentic_fetch
要真正用好agentic_fetch,需要先看清它在整个工具族中的坐标。Crush 的网页相关工具可以分为"无 AI 加工"与"带 AI 加工"两档:
| 工具 | 描述文件 | 能力 | 是否使用 AI 子代理 |
|---|---|---|---|
agent | internal/agent/templates/agent_tool.md | 启动一个仅有glob、grep、ls、view的工具搜索代理 | 是(聚焦本地文件检索) |
fetch | internal/agent/tools/fetch.md.tpl | 抓取 URL 原文为 text/markdown/html,上限约 100KB(MaxFetchSize = 100 * 1024,见 internal/agent/tools/fetch.go#L20-L23),不做任何 AI 处理 | 否 |
web_fetch | internal/agent/tools/web_fetch.md.tpl | 供子代理内部使用的网页抓取,返回 markdown;超过 50KB 的大页面会保存到临时文件供grep/view分析 | 否(子代理的工具) |
web_search | internal/agent/tools/web_search.md.tpl | 通过 DuckDuckGo 搜索,返回标题、URL 与摘要片段,供子代理后续用web_fetch获取全文 | 否(子代理的工具) |
agentic_fetch | internal/agent/templates/agentic_fetch.md | 启动 AI 子代理,自主完成搜索、抓取、提取、摘要与问答 | 是 |
三个核心区分点值得注意:
fetch与agentic_fetch的分工:fetch的描述明确写着 "no AI processing. For analysis or extraction use agentic_fetch",即"需要分析和提取时请用 agentic_fetch"。此外,两个工具都检测了ghCLI 是否可用(见 internal/agent/tools/tools.go#L72-L79):当给定的是精确的 GitHub 仓库、Issue 或 PR 链接时,工具描述会提示改用ghCLI 更高效。agent与agentic_fetch的分工:agent子代理只有本地文件工具(glob/grep/ls/view),用于"不确定能否一次命中时的检索兜底";而agentic_fetch子代理拥有完整的网页工具链,用于"网络内容的理解与提炼"。web_search/web_fetch是内部工具:它们默认不直接暴露给主代理,而是作为agentic_fetch子代理的专属工具集存在。
三、两种工作模式:指定 URL 与自由搜索
agentic_fetch的参数结构定义在 internal/agent/tools/fetch_types.go#L15-L25:
type AgenticFetchParams struct { URL string `json:"url,omitempty" description:"The URL to fetch content from (optional - if not provided, the agent will search the web)"` Prompt string `json:"prompt" description:"The prompt describing what information to find or extract"` } type AgenticFetchPermissionsParams struct { URL string `json:"url,omitempty"` Prompt string `json:"prompt"` }参数语义非常清晰:
prompt(必填):告诉子代理"要找什么、提取什么"。它是唯一的必填参数,缺失会直接报错(见下文校验逻辑)。url(可选):给出明确的待分析 URL。不提供时,子代理进入"自由搜索"模式,自行决定搜索关键词、抓取哪些页面。
对应的两种模式在 internal/agent/agentic_fetch_tool.go#L76-L81 中先行体现——工具会按模式生成给用户看的权限描述:
var description string if params.URL != "" { description = fmt.Sprintf("Fetch and analyze content from URL: %s", params.URL) } else { description = "Search the web and analyze results" }模式一:指定 URL(先抓取,再分析)
当params.URL非空时,子代理不会先做搜索,而是由外层工具直接抓取该 URL 的内容(调用tools.FetchURLAndConvert),再交给子代理分析。这里有一个关键的分流逻辑(internal/agent/agentic_fetch_tool.go#L117-L135):
hasLargeContent := len(content) > tools.LargeContentThreshold if hasLargeContent { tempFile, err := os.CreateTemp(tmpDir, "page-*.md") // ...写入 content 后关闭 fullPrompt = fmt.Sprintf("%s\n\nThe web page from %s has been saved to: %s\n\nUse the view and grep tools to analyze this file and extract the requested information.", params.Prompt, params.URL, tempFilePath) } else { fullPrompt = fmt.Sprintf("%s\n\nWeb page URL: %s\n\n<webpage_content>\n%s\n</webpage_content>", params.Prompt, params.URL, content) }其中LargeContentThreshold = 50000(即 50KB,见 internal/agent/tools/fetch_types.go#L12-L13)。这意味着:
- 小于等于 50KB 的页面:内容直接以内嵌
<webpage_content>的形式拼进子代理的完整提示词中,子代理一次就能读到全部内容; - 大于 50KB 的页面:内容先落盘为临时 markdown 文件,提示词改为"请用
view和grep工具分析该文件"。这是与web_fetch(internal/agent/tools/web_fetch.go#L51-L75)完全一致的策略——避免超大内容撑爆上下文窗口,同时让子代理借助本地检索工具精确命中所需信息。
模式二:自由搜索(子代理自主决策)
未提供url时,提示词改为引导子代理自主搜索(internal/agent/agentic_fetch_tool.go#L136-L139):
fullPrompt = fmt.Sprintf("%s\n\nUse the web_search tool to find relevant information. Break down the question into smaller, focused searches if needed. After searching, use web_fetch to get detailed content from the most relevant results.", params.Prompt)此时子代理拥有完整的搜索-抓取-分析自主权,是agentic_fetch最具"agentic"特性的模式:它自行拆分查询、迭代搜索、挑选最有价值的链接抓取全文,最后汇总答案。
四、子代理的构成:模型、系统提示词与工具集
4.1 使用小模型驱动,兼顾成本
一个值得关注的实现细节:无论agentic_fetch本身跑在什么模型上,其内部子代理都统一使用小模型(internal/agent/agentic_fetch_tool.go#L150-L153):
_, small, err := c.buildAgentModels(ctx, true)构建会话代理时更是显式注释了大模型不参与(internal/agent/agentic_fetch_tool.go#L181-L191):
agent := NewSessionAgent(SessionAgentOptions{ LargeModel: small, // Use small model for both (fetch doesn't need large) SmallModel: small, SystemPromptPrefix: smallProviderCfg.SystemPromptPrefix, SystemPrompt: systemPrompt, DisableAutoSummarize: c.cfg.Config().Options.DisableAutoSummarize, IsYolo: c.permissions.SkipRequests(), Sessions: c.sessions, Messages: c.messages, Tools: fetchTools, })这是"小任务用小模型"的成本控制策略:网页内容分析对推理深度的要求通常低于写代码,用小模型足以胜任,从而对冲"子代理多轮工具调用"带来的额外开销。
4.2 系统提示词:一份完整的"网页内容分析员"指令
子代理的系统提示词来自 internal/agent/templates/agentic_fetch_prompt.md.tpl,由prompt.NewPrompt("agentic_fetch", ...)渲染(internal/agent/agentic_fetch_tool.go#L145-L148),渲染时注入了工作目录(此处即临时目录)、平台与日期等环境信息:
Working directory: {{.WorkingDir}} Platform: {{.Platform}} Today's date: {{.Date}}该模板的规则部分(<rules>)完整定义了子代理的行为边界:
- 回答简洁直接;
- 只关注用户提示中请求的信息;
- 若内容以文件路径提供,用
grep与view高效检索(对应大页面落盘场景); - 相关时引用原文片段支撑答案;
- 找不到所需信息时明确说明,而不是编造;
- 所有文件路径必须使用绝对路径;
- 需要链接页或搜索结果中的信息时,用
web_fetch获取; - 需要更多信息时,用
web_search搜索; - 抓取链接后自行分析内容提取所需信息;
- 必要时可多次抓取链接、多次搜索,直至信息完整;
- 关键要求:回答末尾必须附 "Sources" 章节,列出所有对回答问题有帮助的 URL。
4.3 搜索策略:分解、聚焦、迭代
模板的<search_strategy>段落为子代理提供了方法论级的搜索指引,这也是自由搜索模式质量的核心保障:
- 分解复杂问题:用户问题含多个子问题时,逐个搜索;
- 精准定向查询:多次小范围搜索优于一次宽泛搜索。模板甚至给出了正反例——坏例:"Python 3.12 new features performance improvements async changes";好例:先搜 "Python 3.12 new features",再搜 "Python 3.12 performance improvements",再搜 "Python 3.12 async changes";
- 迭代与细化:首轮结果不佳时更换关键词或提高精度;
- 多角度搜索:为求全面答案,从不同角度分别检索;
- 跟进有价值的线索:发现好来源后抓取它,并顺藤摸瓜查其中的相关链接。
模板还附带了一个完整的示例工作流——"Rust vs Go 用于 Web 服务的优缺点":先分别搜 "Rust web services advantages"、"Go web services advantages"、"Rust vs Go performance comparison",再抓取各搜索结果中最相关的内容。
4.4 子代理工具集:六件套
子代理不是全量工具集,而是精挑细选的六件套(internal/agent/agentic_fetch_tool.go#L165-L174):
webFetchTool := tools.NewWebFetchTool(tmpDir, client) webSearchTool := tools.NewWebSearchTool(client) fetchTools := []fantasy.AgentTool{ webFetchTool, webSearchTool, tools.NewGlobTool(tmpDir, c.cfg.Config().Tools.Glob), tools.NewGrepTool(tmpDir, c.cfg.Config().Tools.Grep), tools.NewSourcegraphTool(client), tools.NewViewTool(c.lspManager, c.permissions, c.filetracker, nil, tmpDir), }各工具的职责:
| 工具 | 作用 | 说明 |
|---|---|---|
web_search | 网络搜索 | 基于 DuckDuckGo,返回标题、URL、摘要;query必填,max_results默认 10、上限 20(见 internal/agent/tools/web_search.go#L39-L59) |
web_fetch | 抓取全文 | 只接受 URL,返回 markdown;大页面(>50KB)保存到工作目录下的page-*.md临时文件 |
glob/grep/view | 本地文件分析 | 用于检索和分析落盘的大页面临时文件 |
sourcegraph | 源码检索 | 涉及代码问题时可检索公开代码库 |
一个重要设计:子代理的内部工具调用不经过用户 hook 拦截。源码中的注释(internal/agent/agentic_fetch_tool.go#L176-L179)解释得很清楚——顶层的agentic_fetch调用本身已经经过了 hook 包装,如果对内部每个工具调用再触发一次 hook,用户的自定义 hook 会在单次委托回合中被重复执行 N 次。
五、权限与会话管理:一次调用,一个受控会话
agentic_fetch走的是完整权限审批链路(internal/agent/agentic_fetch_tool.go#L83-L100):
p, err := c.permissions.Request( ctx, permission.CreatePermissionRequest{ SessionID: validationResult.SessionID, Path: c.cfg.WorkingDir(), ToolCallID: call.ID, ToolName: tools.AgenticFetchToolName, Action: "fetch", Description: description, Params: tools.AgenticFetchPermissionsParams(params), }, ) if err != nil { return fantasy.ToolResponse{}, err } if !p { return tools.NewPermissionDeniedResponse(), nil }权限被拒绝时返回NewPermissionDeniedResponse()——该响应带有StopTurn标记,令主代理循环停止重试(见 internal/agent/tools/tools.go#L64-L70),避免在用户拒绝后反复轰炸。
通过审批后,工具会创建一个临时目录crush-fetch-*(位于配置的 DataDirectory 下)作为子代理的工作目录,并在子代理会话建立后立即对该会话自动批准后续所有内部权限请求(internal/agent/agentic_fetch_tool.go#L199-L202):
SessionSetup: func(sessionID string) { c.permissions.AutoApproveSession(sessionID) },子代理会话的标题固定为 "Fetch Analysis",其输出通过runSubAgent汇入主代理上下文——这意味着用户能看到子代理的分析结论,而无需关心其内部工具调用细节。整个临时目录在工具调用结束后随defer os.RemoveAll(tmpDir)清理,不会污染工作区。
六、参数校验:前置防线
工具调用进入正题前,先经过 validateAgenticFetchParams 三道校验:
prompt不能为空(唯一必填参数);- 会话 ID 必须能从 context 取到(
GetSessionFromContext); - 代理消息 ID 必须能从 context 取到(
GetMessageFromContext)。
其中会话与消息 ID 由tools包通过 context 键session_id/message_id传递(见 internal/agent/tools/tools.go#L44-L52),确保子代理结果能正确归档到发起方会话与消息之下。任何一项缺失都会返回带明确错误文案的文本错误响应。
七、HTTP 客户端与性能基调
工具使用的http.Client有一套统一的调优参数(internal/agent/agentic_fetch_tool.go#L54-L64):
transport.MaxIdleConns = 100 transport.MaxIdleConnsPerHost = 10 transport.IdleConnTimeout = 90 * time.Second client = &http.Client{ Timeout: 30 * time.Second, Transport: transport, }即:单次请求超时 30 秒、连接池空闲上限 90 秒、每主机最多 10 个空闲连接。web_fetch与web_search工具内部复用了相同的默认值(见 internal/agent/tools/web_fetch.go#L25-L36)。这从侧面印证了工具描述中的"Slower and costlier":一次agentic_fetch调用往往包含多轮web_search+web_fetch往返,再叠加子代理的模型推理与多轮工具循环,整体耗时会显著高于单次fetch。
八、实践指引:何时用哪个工具
综合文档声明与源码实现,给出如下选型建议:
- 要原始内容 / API 响应:用
fetch。它不做 AI 加工,上限约 100KB,速度快、成本低;若内容是精确的 GitHub 仓库/Issue/PR 链接且本机装有gh,工具描述会提示直接走ghCLI。 - 要理解、提取、摘要、对比、问答:用
agentic_fetch。它用 AI 子代理消化网页,给出的是结论而非原文。 - 问题需要跨多个来源求证:优先
agentic_fetch的自由搜索模式(不传url),子代理会按模板的搜索策略自行分解查询、迭代搜索并汇总来源。 - 已锁定单一目标页面,但页面较大或结构复杂:给
agentic_fetch传url,让外层先抓取、子代理再分析;超过 50KB 时子代理会自动切换到"落盘 + grep/view 检索"的分析路径。 - 在本地代码库中做模糊检索:用
agent(只有 glob/grep/ls/view),不涉及网络。
需要再次强调的是,agentic_fetch的定位决定了它不应被用于高频、琐碎的取数场景——每一次调用都会启动一个完整的小模型会话并执行多轮工具调用,属于"重武器",应在确实需要语义理解时启用,并通过代理配置的AllowedTools列表按需开放。
结语
agentic_fetch虽只有一行工具描述,背后却是一套完整的"委托式内容理解"架构:从参数校验、权限审批、双模式分流、大内容落盘,到小模型子代理 + 六件套工具 + 结构化系统提示词,再到会话自动批准与临时目录清理。理解它的内部运作,既能帮助你在合适的场景做出正确的工具选择,也能为自定义子代理工具的设计提供一份可借鉴的参考范本。核心实现与模板均可在仓库中直接研读:internal/agent/agentic_fetch_tool.go、internal/agent/templates/agentic_fetch_prompt.md.tpl 与 internal/agent/tools/fetch_types.go。
- AI 应用
- 代码智能体
- 交互助手
- CLI
- MCP Clients
- 人工智能
【免费下载链接】crush
Glamourous agentic coding for all 💘
相关推荐
《AI逐页读书:PDF知识提取与摘要生成器》使用教程
《AI逐页读书:PDF知识提取与摘要生成器》使用教程 1. 项目目录结构及介绍 本项目《AI逐页读书:PDF知识提取与摘要生成器》的目录结构如下: AI rea
人工智能AI 应用如何永久保存微信聊天记录:WeChatMsg数据留痕终极指南
如何永久保存微信聊天记录:WeChatMsg数据留痕终极指南 你是否曾因手机丢失或更换而失去珍贵的聊天记录?那些与亲友的温馨对话、重要的工作沟通、成长的点点滴滴
Crush源码深度解析:理解AI代理工具架构与实现原理
Crush源码深度解析:理解AI代理工具架构与实现原理 Crush是一个基于终端的AI编程助手,它通过精心设计的架构将多种大型语言模型与开发工具无缝集成。本文将
AI 应用代码智能体交互助手CLIMCP Clients人工智能
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考