为了保证留存率,我会先问你几个问题,在使用 Agent 的过程中:
- 是否遇到过跨会话上下文丢失、前后理解不一致?
- 希望 Agent 记住对话中产生的记忆、内容?
- 是否遇到过长上下文污染?越长的会话,模型遵从率、智能程度越低?
- Agent 在开发过程中,是否需要经常检索项目,对项目缺少全局视野?
- Agent 与上游 LLM 之间是否是黑盒系统,较难感知内部?Token 消耗未知,无法针对性治理?
- Agent 使用多了,是否觉得探索知识的欲望、主动阅读文章、源码的意愿更低了?
如果有遇到过这些问题,可以看看我是怎么搭建自己的工作流的。
另外说下,我使用的工具是:Claude Code + Utility.app 接入 LLM API。
Utility.app 是我自用的一个核心工具。
记忆体,跨上下文理解的基石
当使用多个 Agent 时、当跨会话开发时、当会话内产生知识时,你会想到需要什么?
我的回答是:共享记忆体 。我们需要一个能够记录工作进度、对话知识的记忆体,所有消费层使用同一个记忆体,就像人脑一样,不管做什么总是从一个记忆体出发,形成行为的一致性。
那么对于 Agent 来说,记忆体的最佳形态是什么?
本地 MCP 服务 ,MCP 协议被设计为可拔插的,可以随意接入任何支持了 MCP 协议的 Agent,供它们消费。
拥有了这两样东西,我们可以解决两件事:
- 上下文保留、理解一致
- 知识的存储
这还只是明面上的价值,在背后,我们可以思考、分析这些记忆,我们可以提炼记忆进行沉淀,产出更优质的内容;也可以从记忆中生成报告等等。
落到实际,则表现为三层存储记忆架构:
热层保留温热的、新的记忆;冷层保留长期有用的记忆;最终沉淀到笔记层,目的是永久存储与方便人工阅读。
remember / recall 是本地 MCP 服务内置的两个工具,用于记忆的写入与检索,Agent 通过调用这两个工具来操作记忆。
Proxy 网关,扩展的关键
记忆体 解决了跨会话理解、多 Agent 共享记忆的问题,我们现在聚焦到长上下文污染 与黑盒系统的问题。
黑盒系统破局需要 Proxy 网关很好理解,在 Agent 与上游 LLM 厂商插入一层代理层,就可以使黑盒系统透明,那么长上下文污染为什么会需要代理层呢?
我们知道,在长对话中,初始的系统提示词、规则、或者是工具描述,非常容易被后续的上下文污染,导致模型的注意力更关注最新内容,而忽略了系统提示词、规则、工具描述,造成的后果可能是:
- 行为漂移
- 遵从率下降
- 工具调用意愿下降
- 智能降低
这种时候一般做法是新开会话,我认为这很麻烦,所以我找到了另一个方式:动态提示词注入。
它的工作原理很简单,既然 LLM 对于旧的消息注意力下降,那就将核心的提示词注入到每条最新的用户消息中,使其具有最高优先级。
为什么是注入到用户消息中呢?而不是到系统提示词位置?这个决策来自长久的观察,在使用 DeepSeek 这种较智能的 LLM 时,注入不缓存的系统提示词通常不会有太大的问题,但对于像 小米 mimo 这种智能程度较低的 LLM 来说,它更愿意遵守最新的用户消息。
这种方式的效果非常好,但代价也很明显,由于每轮用户消息都注入同样的内容,会增加 Token 消耗 ,所以一般动态注入的提示词偏向轻量、核心、全局可用 ,对于项目生效的提示词而言,更适合用 AGENT.md/CLAUDE.md。
Token 分析治理,省钱必做的一步
代理还有一个核心的价值是黑盒系统可观测了,我们可以记录每个请求的输入输出、模型的请求成功率、延迟、缓存率,这些指标具有很高的价值,我们可以根据这些内容来分析、量化 Token,并据此进行针对性的治理。
在漫长的治理过程中,我发现核心的就几点:
- 提高缓存率
- 不破坏缓存
- 减少输入
不破坏缓存 是一个很重要的前提,代理层能够在请求转发到上游前操作消息,一般能想到的做法是在转发前压缩、裁剪、剔除消息,以期达到减少 Token 输入的目的,这种做法是不完全正确的,因为这会破坏缓存,使每条断了缓存的消息都以非缓存的价格计费。
在进行 Token 治理时,应该从成本的维度去分析,而不是 Token 输入的多少。
也就是说,当大量缓存输入的成本超过因裁剪破坏缓存的成本时,是可以考虑裁剪历史消息的。
减少输入就很好理解了,Agent 在使用过程中通常会进行多次工具调用,这些工具会产生大量的Token 输入,有些可能只使用一次,却在后续的每次对话中都携带,即使以缓存价格计算,但数量暴增时也会导致成本的增加。
所以我们需要针对工具输出内容进行瘦身,比如 Bash 只看是否有 warning/error。
我做的 Token 治理有:
- 减少重复内容:同一会话反复获取到同一份工具输出内容时,第二份起替换成一句短提示,保留第一次的全文。
- 裁剪 shell 输出:超长命令输出保留前 70% 和后 30%,中间插入截断标记;JSON 做无损压缩。
- 注入保证幂等性:前置注入保证幂等性,不破坏缓存
- 工具限流:减少内置工具的默认响应
依赖图,全局感知视野
使用过 Claude Code 这类 Agent 开发项目的应该都有一个感受,缺乏全局视野的感知能力,可能这次实现了一个组件、工具,下次有相同需求时就忘了,并重复实现;或者经常需要全局查找某个组件、工具。
这是因为缺失全局视野能力 的原因,或者说是整个项目的依赖图。
针对这个痛点,我给 Utility.app 加了一个扫描依赖图的功能,表现为 cli 命令:
sh
utility -a "agent"
# eg. utility -a claude
它做了这样几件事,启动扫描器,扫描项目符号,生成依赖图,并存储到 .utility/deps.sqlite 库中,然后启动 Agent,进行 Agent 终端,控制权回到 Agent,而 Utility.app 则在后台侦听文件变化并更新依赖图。
然后 Agent 可以通过本地 MCP 服务暴露的 project_search / project_structure / project_exports / project_packages 工具查询。
知识面板,主动推送新鲜知识
这是关于个人成长的问题,我想解决它,问题的关键在于,Agent 用多了,主动阅读、探索新知识的意愿变低,我希望有一个主动弹出的面板,能展示一些我从未见过,或者说感兴趣的内容,能够让我花点时间去阅读。
为什么是从未见过的内容呢?我们知道,我们有一个记忆体,里面存了一些知识,为什么不能从里面提取一些内容来展示呢?
问题的关键在于,记忆体中的内容都是对话中产生的,这些内容已经在我们脑海中了,再次看到它不能让我们的大脑感到兴奋。所以我们需要一点未知的、感兴趣的新内容。
它的运作方式是这样的,我们会配置一些感兴趣的主题,然后大模型会去爬取有关主题的内容,当时间间隔到时,它会抽取一条知识显示在知识面板上。
这些核心能力在我的 Utility.app 中,我把它开源在:yuanyxh/utility