ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

deepseek-harness Web Seam 契约精简实录:一次针对“无人消费字段“的接口裁剪决策

2026/9/19 4:33:29 拓冰建站 浏览量
deepseek-harness Web Seam 契约精简实录:一次针对“无人消费字段“的接口裁剪决策 deepseek-harness Web Seam 契约精简实录一次针对无人消费字段的接口裁剪决策【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness本文基于 deepseek-harness 仓库中的技术决策记录 2026-07-12-prune-unused-web-seam-fields.md 展开。它记录了一次已完成Status: implemented的接口精简将 web capability 的搜索/抓取结果回显字段、按请求级超时覆盖参数与单字段执行上下文包装器从契约中删除。读完本文你将理解这套ctx.webseam 的精简动机、裁剪前后的契约差异、超时与取消职责的归属以及如何在源码与测试中验证这类死字段裁剪。背景Web capability seam 的职责边界在 deepseek-harness 中web 访问能力被抽象为一条独立的 capability seamctx.web由 packages/web/web 包提供。按 packages/web/web/src/types.ts 顶部注释的说明搜索与抓取deliberately share one seam so provider selection, cancellation, errors, and product configuration have one owner, while retaining separate request and result types——即搜索与抓取共享同一条 seam使 provider 选择、取消、错误与产品配置有唯一归属但保留各自的请求/结果类型。这条 seam 的核心词汇表包括WebSearchRequest一次搜索请求仅含query与可选的maxResults上限WebSearchResult规范化搜索结果含contentprovider 生成的答案文本、sources[]可引用来源列表、truncated是否因maxResults被截断WebFetchRequest一次抓取请求仅含urlWebFetchResult规范化抓取结果含最终url、statusCode、解码后的body与truncatedWebSearchProvider/WebFetchProviderprovider 接口各自暴露id、available()与执行方法。而本次精简前的契约在此基础上还携带了一批每个实现都会填充、却没有任何生产消费者读取的字段。下面逐一还原。问题三个无人消费的字段族决策记录在 Problem 一节中把问题归纳为三类1. 结果回显result echoes——providerId与query精简前的WebSearchResult.providerId、query以及WebFetchResult.providerId属于结果回显它们把请求端已知的信息由哪个 provider 执行、查询词是什么再原样带回结果端。记录指出tool-web在格式化输出时只使用content/sources/truncation搜索或最终 URL/状态码/正文/截断抓取no other runtime reads them——整个运行时没有任何代码读取这些字段。2. 按请求级超时覆盖——WebFetchRequest.timeoutMsWebFetchRequest.timeoutMs同样never set by a production callertool-web只提供 URL超时由工具定义ToolDefinition.timeoutMs配合exec.signal作为调用方截止时间并以本地 provider 的配置默认值作为兜底backstop。这个无人使用的按请求覆盖参数却迫使web-fetch-local额外暴露maxTimeoutMs、对两个超时来源做钳制clamp并为没有任何产品路径能触发的优先级规则编写文档与测试。3. 单字段执行上下文包装器——WebExecContextWebExecContext是又一个只含一个字段的包装器每个调用方都只分配{ signal }每个 provider 都立即解包exec?.signal而契约中并不存在第二个执行控制字段。它为一次性使用引入了整条 wrap/unwrap 管线。决策裁剪到每个保留字段都被消费决策记录给出了精简后的契约形态删除搜索/抓取结果的providerId回显与搜索结果的query回显——调用方本已持有请求与 provider 选择信息provider 以boolean 返回的available()方法暴露可用性取代携带reason的状态对象抓取请求不再有按请求级超时与maxTimeoutMs钳制本地 provider 保留其可配置的默认超时工具保留自己的截止时间provider 方法直接接收可选的AbortSignal取代单字段的WebExecContext包装器。同时记录强调All web implementations and the model-facing tool use the smaller contract并且保留不变的部分包括接口/实现/消费者包的划分、provider 选择、来源引用citations、最终 URL/状态数据、截断报告与安全限制。源码印证精简后的契约现状当前仓库中的 packages/web/web/src/types.ts 已完整呈现精简后的契约。例如WebSearchResult只有三个字段export interface WebSearchResult { readonly content?: string readonly sources: readonly WebSearchSource[] readonly truncated: boolean }WebFetchRequest更是收缩为单个url字段且类型注释直接记录了这一决策的动机The request deliberately omits timeout, format, prompt, and extraction controls: cancellation is a direct execution argument, while presentation and higher-level LLM concerns belong outside safe retrieval.provider 接口同样印证了布尔available() 直接传AbortSignal的决策export interface WebSearchProvider { readonly id: string available(): boolean search(request: WebSearchRequest, signal?: AbortSignal): PromiseWebSearchResult } export interface WebFetchProvider { readonly id: string available(): boolean fetch(request: WebFetchRequest, signal?: AbortSignal): PromiseWebFetchResult }在运行时层面packages/web/web/src/index.ts 的WebRuntime中search/fetch方法均把signal直接转发给 providerasync search(request: WebSearchRequest, signal?: AbortSignal): PromiseWebSearchResult { const provider resolveProvider({ ... }) const result await provider.search(request, signal) return capSources(result, request.maxResults) }而resolveProvider的选择逻辑完全基于available()布尔值与注册表配置了 id 但未注册 →WEB_PROVIDER_CONFIGURED_MISSING已注册但不可用 →WEB_PROVIDER_CONFIGURED_UNAVAILABLE未配置且仅有一个可用 provider → 自动选中多个可用 →WEB_PROVIDER_AMBIGUOUS无可用 →WEB_PROVIDER_UNAVAILABLE。这与决策记录中providers expose availability as a boolean-returning method以及resolution checks onlyavailable的描述完全一致——被删掉的reason字段原本用于生成更具体的不可用诊断而现在统一走通用诊断。超时职责的最终归属三层各司其职WebFetchRequest.timeoutMs被移除后超时语义在三处独立成立互不重叠工具层截止时间ToolDefinition.timeoutMs在 packages/web/tool-web/src/fetch.ts 中web_fetch工具通过applyWebFetchTool(ctx, timeoutMs, maxOutputChars)注册超时被挂在defineTool的timeoutMs上由dsh-tool-call-timeout-policy负责执行并通过exec.signal传递。文件头部注释明确写道Timeout is deployment policy, not a model argument——超时是部署策略而非模型参数因此工具的 schema 中只有urlparameters: { url: { type: string, required: true, description: The HTTP(S) URL to fetch. }, },execute中调用 seam 时只传 URL 与调用方信号const result await ctx.web.fetch( { url: input.url }, exec.signal, )provider 层配置默认值backstop在 packages/web/web-fetch-http/src/provider.ts 中HttpFetchProvider.fetch用本地配置的limits.timeoutMs作为默认超时兜底using d deadline(signal, this.limits.timeoutMs, WEB_FETCH_TIMEOUT) return await this.followAndRead(request.url, d.signal)deadline把调用方信号与本 provider 超时合并为单一信号WEB_FETCH_TIMEOUT错误码用于区分本 provider 超时与外部取消。HttpFetchLimits中的timeoutMs由插件的 schemastery Config 提供默认值属于部署配置而非按请求参数。取消cancellationAbortSignal作为直接执行参数贯穿工具 → seam → provider。测试 packages/web/tool-web/tests/tool-web.spec.ts 对此有明确断言it(forwards the required caller signal to web_fetch)验证了seen.signal与传入的controller.signal/testToolSignal严格相等it(validates url (non-empty), no timeout parameter)则验证了模型面 schema 不再暴露任何 timeout 参数。从源码结构看这套分工正是决策记录中the tool retains its own deadline, the local provider retains its configurable default timeout的具体实现——精简移除的是可配置性而非安全边界因此 Consequences 一节强调The provider still has a deployment-configurable timeout and respects cancellation, so the simplification removes configurability rather than a safety bound.保留不变的契约面选择、引用、截断与安全精简没有触及任何被生产代码消费的字段。决策记录明确列出保留项逐一可在源码中验证provider 选择WebRuntimeConfig.searchProvider/fetchProvider及$DSH_WEB_SEARCH_PROVIDER/$DSH_WEB_FETCH_PROVIDER环境变量packages/web/web/src/index.ts来源引用WebSearchSource的url/title/snippet/publishedAt由tool-web渲染为带引用的 markdown 列表并附上cite the relevant URLs的固定提示packages/web/tool-web/src/search.ts最终 URL/状态WebFetchResult.url/statusCode非 2xx 响应被视为结果而非错误截断报告WebSearchResult.truncated由 seam 的capSources统一执行sources.slice(0, maxResults)WebFetchResult.truncated覆盖字节与字符两种上限安全限制web-fetch-http的公共 IP 校验、同源重定向限制、maxResponseBytes/maxBodyChars大小上限等全部保留。备选方案与决策后的权衡决策记录在 Alternatives considered 中坦诚记录了被否决的方案保留自描述结果、按请求级截止时间与可扩展的执行上下文对象。其论据是——结果回显可服务于通用遥测请求超时可服务于可信的程序化调用方包装器为未来控制项留出空间。但no such consumer/second field exists当前既没有读取这些回显的遥测消费者也没有需要第二个执行控制字段的调用方。为此承担重复的身份信息、第二套截止时间策略、贯穿每个 provider 的包装/解包管道只会让契约更难实现、更难解释。因此文档给出了明确的未来指引如果遥测或每次调用预算控制真正到来届时再定义哪个截止时间胜出、provider 身份在哪里被观测、多个控制项是否足以支撑一个上下文对象。这是典型的现在不做未来需要时再做的 YAGNI 决策同时为未来保留了明确的演进判据。在维护者视角下的方法论价值这份记录本身属于仓库 .agents/notes/archived/simplification 目录下的简化类 agent note2026 年 6 月至 8 月间同系列约有二十余份如2026-06-20-prune-dead-seam-methods.md、2026-07-04-drop-inert-request-knobs.md、2026-07-04-prune-write-only-fs-surface.md采用统一的Problem / Decision / Alternatives considered / Consequences结构。从这批记录与仓库源码的对应关系可以推断deepseek-harness 对接口契约采取的是**无消费者即无字段**的维护纪律每个保留字段要么被生产代码消费要么是执行 provider 请求所必需Every retained web request/result field is consumed by production code or required to execute the provider request工具对模型可见的输出、provider 回退、中止行为、配置超时兜底、截断与引用在删除按请求超时优先级分支与执行上下文包装器之后依然完整覆盖验证手段依赖类型系统与测试双重保障available()布尔化与signal直传都体现在接口签名中编译期即可约束tool-web.spec.ts中的seen.signal断言与no timeout parameter断言则锁定了运行时行为。结语本次精简从 web seam 契约中删除了三类无人消费的字段结果回显providerId、query、按请求级超时覆盖timeoutMs/maxTimeoutMs与单字段执行上下文包装器WebExecContext。其结果是更小的契约表面积、更直接的责任划分——超时归部署配置取消归AbortSignal直传provider 可用性归布尔方法——同时完整保留了选择、引用、截断与安全语义。对于正在阅读 deepseek-harness 源码的开发者这份记录与其说是一次历史变更不如说是理解当前ctx.web契约设计的钥匙每一个保留字段都能在 packages/web/web/src/types.ts 中找到消费方而每个被删除的字段都能在这里找到删除的理由。备注本记录对应的中文翻译版本见 2026-07-12-prune-unused-web-seam-fields.zh.md同系列简化决策可参考 .agents/notes/archived/simplification 目录下的其余 Agent Note。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考