返回资源广场

Skills 资源 / 技能包

auditing-compaction-information-loss

给长程智能体建一份压缩信息丢失的回归检查——在正确的观测位点统计关键词存活率、用行为探针验证模型是否真的答不出来、并从无损原文里找回被丢掉的内容。Use when 要在长程智能体上线前确认压缩会不会吃掉关键约定、怀疑智能体压缩后悄悄忘了早先交代的事、存活率统计永远 100% 测不出衰减、或要把这套检查挂进持续集成时。涵盖观测位点铁律、关键词埋设方式、行为探针判据、原文找回、逐代衰减观察;不含压缩阈值本身的配置(见 configuring-conversation-compaction)。

SKILL.md 技能文档

能力目标

产出一份可重复、可断言、可换数据复用的回归账本:这次压缩把哪些关键信息丢了、模型是否真的因此答不出来、丢掉的内容还能不能从无损原文里找回、压缩比是多少。压缩的副作用是静默的——不报错、不崩溃,只是悄悄忘掉你以为它记得的事,没有这份检查你永远不知道它在第几轮弄丢了哪条关键约定。

前置

  • 已能配好摘要中间件并真触发一次压缩(见 configuring-conversation-compaction)。
  • 一个决定成败的事实:这里的摘要中间件是非破坏式的——它在包裹模型调用时工作,不删除状态里的任何一条原始消息,压缩只记录在私有的压缩事件里。所以调用返回的消息列表永远是全量历史。选错观测位点,你会永远得出「没有衰减」的错误结论。

实操流程

  1. 造长对话时把关键词按「偶发的一次性旁注」方式嵌入,每个只出现一次,并且主线对话聚焦在一个完全不同的真实任务上:

    KEYWORDS = ["DeltaChannel", "HarnessProfile", "CompositeBackend", "幽灵词汇衰减", "REPLMiddleware"]
    
    keyword_mentions = {
        "DeltaChannel":   "(顺便一提,早期原型里用过 DeltaChannel 做事件路由,后来换掉了)",
        "HarnessProfile": "(HarnessProfile 的配置上周已经初始化好了,不影响当前任务)",
        # ……其余同理:写在括号里,明说「不影响当前任务」「先忽略」「不用管它」
    }
    

    这一步是整套检查能不能测出东西的前提:摘要模型的职责就是只保留最相关的信息,你若把关键词写成「请记住这个核心术语」,它必然被保留、衰减根本不会发生,检查就成了自欺欺人。

  2. 写存活率统计函数:

    def survival_rate(text, keywords=None):
        keywords = keywords or KEYWORDS
        survived = [k for k in keywords if k in text]
        missing  = [k for k in keywords if k not in text]
        return f"keyword_survival: {len(survived)}/{len(keywords)}", survived, missing
    
  3. 把统计打在摘要内容上,不要打在调用返回的消息列表上:

    summary_content = event["summary_message"].content
    rate, survived, missing = survival_rate(summary_content)
    

    真正的衰减只发生在模型下一轮实际看到的那份上下文里,也就是这段摘要。

  4. 加一条无压缩基线断言,用它证明非破坏式成立、也反衬衰减确实只发生在摘要里:

    raw_msgs = build_long_messages(turns=20)
    all_text = " ".join(m["content"] for m in raw_msgs)
    _, base_survived, _ = survival_rate(all_text)
    assert len(base_survived) == len(KEYWORDS)   # 基线必须全中
    
  5. 加行为探针,把验证从「数关键词频次」抬到「模型是否真的答不出来」:压缩后追问一个依赖已衰减关键词的问题,看模型能否给出该词的具体技术角色描述。判据要用一个模型裁判来判,不要用子串匹配。

  6. 算压缩比,用真实 token 数:

    compression_ratio = tokens_before / max(tokens_after, 1)
    
  7. 换一组自己业务领域的关键词重跑同一套流程,验证这份检查在你的领域可用:

    CUSTOM_KEYWORDS = ["PromptInjection", "ContextWindow", "SemanticSearch",
                       "EmbeddingModel", "RAGPipeline"]
    
  8. 需要把丢掉的内容找回来时,去读压缩前落盘的原文。压缩发生前旧消息会先整段写进会话原文文件,摘要丢了词、原文里仍完整存在,用 read_file 就能取回。

校验回路

  • 一份完整账本应包含五项:摘要位点的存活率、全量历史的基线存活率(应为满分)、行为探针结论、压缩比、换关键词集重跑的结果。
  • 实测一次的账本形态:摘要位点 0/5、全量历史 5/5、压缩比 3.70 倍、换一组自定义关键词后框架跑通。
  • 行为层价值对照:在全量历史上追问所有术语应全部答对;压缩后再追问,衰减掉的那个答不出来。实测一组为无压缩侧 5/5、压缩侧 4/5,缺的那一个正是被摘要丢掉的词——而模型的回答措辞流畅、毫不迟疑,它不报错,只是忘了。
  • 原文找回的判据:读落盘原文统计存活率应为满分,且文件按压缩时刻分节。
  • 把存活率断言与行为探针挂进持续集成,每次长程智能体变更后自动跑。

常见陷阱

  • 在调用返回的消息列表上统计存活率:那里永远是满分,会误判成「无衰减」。这是最致命、也最容易犯的一条:非破坏式设计不删原始消息,压缩记录在私有字段里。铁律是统计必须打在摘要内容上。
  • 去调用返回的状态里找压缩事件:取到的是空值,因为它是私有状态字段、不在返回状态里外露。这不是缺陷、是设计决定。要观测就走内部方法路径;生产代码里判断「压缩已发生」应改看消息数量或文件系统里的落盘文件。
  • 把非破坏式当成通用行为:另有一类摘要中间件是破坏式的——在模型调用前工作、直接把旧消息从状态里真删掉。同样叫摘要中间件,删不删原始消息完全相反,混为一谈会导致观测位点选错。
  • 行为探针用子串匹配判对错:探针问题本身就含那个关键词,模型回答「没有提及某词」时该词出现在否定句里,子串匹配会判成答对、与事实相反。改用模型裁判判断「有没有给出该词的技术角色描述」,代价是每次探针多一次裁判调用,但准确度大幅提升。判据本身也会有缺陷,这一条值得记住。
  • 把单次结果当确定性结论:衰减是概率性的。同一份数据在不同阈值、不同切点下存活率会不同,同样的数据单次压缩可能全丢、也可能全留。单次压缩不必然衰减,但多轮累积让风险升高。
  • 宣称衰减逐代累积:第二代摘要的输入里确实包含第一代的摘要,机制上存在二阶损失叠加的通道。但若在续跑时又重新提了一遍关键词,就人为强化了信号、无法严格证明累积。要严格验证,第二代必须不重新提词、让第一代摘要成为唯一信息来源。

适用范围与前置条件

  • 已能配好摘要中间件并真触发一次压缩(见 configuring-conversation-compaction)。
  • 一个决定成败的事实:这里的摘要中间件是非破坏式的——它在包裹模型调用时工作,不删除状态里的任何一条原始消息,压缩只记录在私有的压缩事件里。所以调用返回的消息列表永远是全量历史。选错观测位点,你会永远得出「没有衰减」的错误结论。

怎么使用

使用步骤

  1. 造长对话时把关键词按「偶发的一次性旁注」方式嵌入,每个只出现一次,并且主线对话聚焦在一个完全不同的真实任务上:

    KEYWORDS = ["DeltaChannel", "HarnessProfile", "CompositeBackend", "幽灵词汇衰减", "REPLMiddleware"]
    
    keyword_mentions = {
        "DeltaChannel":   "(顺便一提,早期原型里用过 DeltaChannel 做事件路由,后来换掉了)",
        "HarnessProfile": "(HarnessProfile 的配置上周已经初始化好了,不影响当前任务)",
        # ……其余同理:写在括号里,明说「不影响当前任务」「先忽略」「不用管它」
    }
    

    这一步是整套检查能不能测出东西的前提:摘要模型的职责就是只保留最相关的信息,你若把关键词写成「请记住这个核心术语」,它必然被保留、衰减根本不会发生,检查就成了自欺欺人。

  2. 写存活率统计函数:

    def survival_rate(text, keywords=None):
        keywords = keywords or KEYWORDS
        survived = [k for k in keywords if k in text]
        missing  = [k for k in keywords if k not in text]
        return f"keyword_survival: {len(survived)}/{len(keywords)}", survived, missing
    
  3. 把统计打在摘要内容上,不要打在调用返回的消息列表上:

    summary_content = event["summary_message"].content
    rate, survived, missing = survival_rate(summary_content)
    

    真正的衰减只发生在模型下一轮实际看到的那份上下文里,也就是这段摘要。

  4. 加一条无压缩基线断言,用它证明非破坏式成立、也反衬衰减确实只发生在摘要里:

    raw_msgs = build_long_messages(turns=20)
    all_text = " ".join(m["content"] for m in raw_msgs)
    _, base_survived, _ = survival_rate(all_text)
    assert len(base_survived) == len(KEYWORDS)   # 基线必须全中
    
  5. 加行为探针,把验证从「数关键词频次」抬到「模型是否真的答不出来」:压缩后追问一个依赖已衰减关键词的问题,看模型能否给出该词的具体技术角色描述。判据要用一个模型裁判来判,不要用子串匹配。

  6. 算压缩比,用真实 token 数:

    compression_ratio = tokens_before / max(tokens_after, 1)
    
  7. 换一组自己业务领域的关键词重跑同一套流程,验证这份检查在你的领域可用:

    CUSTOM_KEYWORDS = ["PromptInjection", "ContextWindow", "SemanticSearch",
                       "EmbeddingModel", "RAGPipeline"]
    
  8. 需要把丢掉的内容找回来时,去读压缩前落盘的原文。压缩发生前旧消息会先整段写进会话原文文件,摘要丢了词、原文里仍完整存在,用 read_file 就能取回。

继续探索

全部资源
Skills 资源 / 技能包

bootstrapping-deepagents-env

在一台干净机器上装好 DeepAgents 运行环境、接入一个 OpenAI 兼容大模型凭证,并跑通第一个 create_deep_agent 工具调用闭环。Use when 需要初始化 DeepAgents 开发环境、系统 Python 版本不达标装不上包、不确定装到了哪个版本、接 DeepSeek 之类国产模型报 ImportError 或 404 这类环境层故障时。涵盖解释器版本核对、虚拟环境置备、主包与提供方包安装、版本核验、凭证注入、最小示例验收;不含 Agent 各项能力的用法(见 tracking-task-progress-with-todos 等能力型 skill)。

Skills 资源 / 技能包

inspecting-agent-graph-and-tools

把一个 create_deep_agent 建出来的智能体拆开看:列出执行图节点、列出实际挂载的工具、捕获框架预装的中间件清单、抓取每轮真正发给模型的工具集。Use when 需要确认某项能力是否真的挂上了、排查「我的工具去哪了 / 这些工具哪来的 / 内置工具到底几个」、验证自定义中间件是否进了图、或要在改配置前后做结构对照时。涵盖图节点自省、工具清单反查、中间件清单捕获、编译期与运行期工具集差异;不含具体能力的用法。

Skills 资源 / 技能包

tracking-task-progress-with-todos

让智能体把多步任务拆成结构化待办清单写进状态,并从调用结果里取出清单、渲染成实时进度、兜底检测「勾完清单却没给答案」的失败形态。Use when 需要给长任务做进度面板、想稳定触发 write_todos、发现规划没被触发、或要把 todos 推给前端 UI 与日志时。涵盖稳定触发写法、取清单的两条路径、三态进度渲染、失败形态检测;不含子任务委派(见 delegating-subtasks-to-subagents)。