语义被切碎之后,我找到了缝回去的方法

原创 build in Public MingBuilds

在这里插入图片描述


上一篇我聊到,AI 产品真正的单位可能不是 Function,而是语义连续性。

那个认知,是我用 Coding Agent 去做 Agent 的时候,慢慢感觉到的。

但"感觉到"和"解决掉"之间,隔着一道巨大的鸿沟。

意识到语义在被切碎之后,我做的第一件事不是去翻论文,而是回到自己的项目里,一行一行地看——到底是哪一行代码,把语义切断的。

我盯着一个 if intent == "complaint" 看了很久。

然后我意识到:模型在上一步明明理解了"这个用户语气里带着疲惫,他其实不是在投诉,他只是想要一个解释"。但这段理解,在进入我的 if-else 的那一瞬间,就被压缩成了一个字符串 "complaint"

所有的温度、所有的语气、所有说不清道不明的东西——全没了。

那天晚上我开始动手改。改着改着,逐渐摸出了一套方法。

这一篇,就是把这套方法交出来。

不是玄学,不是"你应该转变思维"。

是三层诊断、四条原则、五个开源项目。

是你今天就能拿去审视自己代码的东西。


01 先搞清楚:语义到底是在哪一层断掉的

在动手之前,我们得先诊断。

我在上一篇提到"低级语义在强行控制高级语义",但这句话太抽象了。翻译成工程语言,语义断裂通常发生在三个地方:

第一层:控制流层。

你用 Python 写了一棵决策树。if intent == "complaint": route_to_support()。模型原本理解的是"这个用户语气里带着失望,但他其实是想要一个解释",但你的代码只看到了 complaint 这个字符串。

语义在进入 if-else 的那一瞬间,就从一段连续的理解,变成了一个离散的标签。

第二层:记忆层。

用户跟你的 Agent 聊了 40 分钟。你的系统把这 40 分钟压缩成了三行 summary:“用户讨论了项目进度,表达了对延期的担忧,希望加速推进。”

原文里那句"其实我不是怪你们慢,我是怕老板下周问我的时候我没法交代"——没了。

语义在 summary 的那一刀下,从一段有温度的叙事,变成了一张冷冰冰的摘要卡片。

第三层:传输层。

Agent A 完成了一个子任务,需要把结果传给 Agent B。你的代码把结果序列化成了 {"status": "success", "result": "migration completed", "errors": 0}

但 Agent A 在执行过程中发现了一个"虽然没报错但感觉不太对"的边缘情况。这个直觉没有字段可以装。

语义在 JSON 序列化的那一刻,从一个有直觉、有判断的过程叙事,变成了三个平坦的键值对。

不知道你有没有这种感觉?

这三层,恰好对应了三个解决方案。


02 控制流层:把方向盘还给模型

在这里插入图片描述

问题的本质

传统 Agent 架构里,代码是导演,模型是演员。

代码说"现在分析意图",模型就分析意图。代码说"现在调用工具",模型就调用工具。代码说"现在生成回复",模型就生成回复。

模型永远只看到"这一步"的剧本,看不到"整出戏"的脉络。

每一次代码的 await llm.call(),都是一次语义的截断。模型在上一步理解的那些微妙的、模糊的、说不清楚的东西,在函数返回值里全部丢失了。

解决方案:让模型自己开车

2025 年 3 月,OpenAI 把实验性的 Swarm 框架升级为了正式的 Agents SDK。虽然 Swarm 已经废弃,但它留下的核心理念被完整继承了下来:

Conversation as Control Flow — 用对话代替代码来驱动流程。

什么意思?

以前你写的是:

# 旧方式:代码做导演
intent = await classify_intent(user_message)
if intent == "refund":
    result = await handle_refund(order_id)
    response = await generate_response(result)

现在应该写的是:

# 新方式:模型做导演
refund_agent = Agent(
    name="退款专家",
    instructions="""你是退款处理专家。
    当用户的问题超出退款范围时,
    把完整的对话交给通用客服。""",
    functions=[process_refund, check_order],
    handoffs=[general_support_agent]
)

看出区别了吗?

第一种写法,在决定什么时候调用什么。模型只是一个被调用的函数。

第二种写法,模型在决定什么时候调用什么。而且更关键的是——当它把任务"交接(Handoff)"给另一个 Agent 时,传递的不是一个 JSON,而是完整的对话历史。

整段对话的语义,一个字都没丢。

这就是"Conversation as Control Flow"的本质:不是模型更强了,而是你不再人为地打断它的思考了。

话说回来,这不是说完全不要代码控制。关键是要分清楚:确定性的操作(查数据库、调 API)交给代码,不确定性的判断(理解意图、决定下一步)交给模型。

📌 落地资源:OpenAI Agents SDK

Swarm 的生产级继任者。核心概念只有三个:Agent、Tool、Handoff。

它最性感的设计是:Agent 之间的交接,传递的是完整的 Messages 数组,而不是结构化的中间状态。

GitHub:openai/openai-agents-python


03 记忆层:别再切片,开始写日记

在这里插入图片描述

问题的本质

现在大多数 Agent 的"记忆",本质上是一个向量数据库。

用户说过的话,被切成 512 个 token 一段的 chunk,算一个 embedding,存进去。下次需要的时候,用余弦相似度捞出来。

这个流程有一个致命的问题:

它只能记住"用户说过什么",记不住"用户是什么样的人"。

你把一个人说的 100 句话切成 100 个片段存进向量库,每个片段都是孤立的。你能检索到"用户提到过他喜欢简洁的设计",但你检索不到"这个用户是一个注重效率、讨厌废话、但又偶尔需要情感确认的技术管理者"。

后者是一段连续的、整合性的理解。它不在任何一个 chunk 里,它在 chunk 和 chunk 之间的关系里。

向量数据库存储了语义的碎片,但丢失了语义的连续性。

解决方案:让 Agent 自己写日记

2026 年 4 月,Mem0 发布了一次重大更新。它做了一件很反直觉的事:

放弃了 UPDATE 和 DELETE 操作。改用 ADD-Only(只追加)的记忆模式。

为什么?因为他们发现,当系统允许"覆盖"旧记忆时,很多微妙的语境信息会被新信息冲掉。

比如,用户三个月前说"我喜欢 React",上周说"我最近在学 Svelte"。旧系统会把"喜欢 React"更新为"喜欢 Svelte"。但真实的语义是:这个用户的技术品味在演化,他可能正在从 React 生态向更轻量的方向迁移。

ADD-Only 模式保留了这个演化轨迹。

更关键的是 Mem0 的三重检索机制

语义相似度(向量搜索)
        ×
关键词匹配(BM25)
        ×
实体关联(Entity Linking)
        ↓
    融合打分 → 最终结果

它不只是"找到最相关的记忆",而是"理解记忆之间的关系"。

当用户说"那个项目"时,系统不仅能找到"项目"相关的记忆碎片,还能通过实体关联追溯到这个项目涉及的人、时间线、用户对它的情感态度。

这就是我说的"写日记"——不是把信息存成表格,而是让 Agent 像写日记一样,记录带有时间、情感和因果关系的连续叙事。

Mem0 在 LoCoMo 基准测试上的得分从 71.4 跳到了 91.6,LongMemEval 从 67.8 跳到了 94.8。这不是小数点后的微调,这是质变。

📌 落地资源:Mem0 — The Memory Layer for AI

不是又一个 RAG 封装。它是一个独立的记忆架构组件,支持 User、Session、Agent 三个作用域。

最新的 ADD-Only 算法 + 多信号融合检索,平均每次检索只消耗 7000 tokens,远低于全量上下文方案的 25000+。

GitHub:mem0ai/mem0

另一个值得关注的项目是 Letta。

Letta 的思路更极端——它直接借鉴了操作系统的内存管理模型,给 Agent 设计了一个分层的记忆体系:

  • 核心记忆(Core Memory):始终驻留在上下文窗口里的关键信息,类似 CPU 寄存器
  • 归档记忆(Archival Memory):大容量的长期存储,类似硬盘
  • 回忆记忆(Recall Memory):对话历史的检索层,类似内存

Agent 自己决定什么时候把信息从"寄存器"搬到"硬盘",什么时候从"硬盘"调回"内存"。

这就是把"记忆管理"从开发者的手里,交到了模型自己手里。

📌 落地资源:Letta(前身 MemGPT)

OS 启发的分层记忆架构。Agent 自主管理自己的记忆生命周期。

GitHub:letta-ai/letta


04 传输层:别翻译,直接递原文

在这里插入图片描述

问题的本质

Agent 和外部世界之间,隔着一层"翻译"。

你的 Agent 想读一个文件,代码会先把文件内容读出来,提取关键信息,组装成一段描述,再塞进 prompt。

你的 Agent 想查数据库,代码会先执行 SQL,把结果转成 JSON,过滤掉"不必要"的字段,再传给模型。

每一次"翻译",都是一次语义的有损压缩。

而且更要命的是——开发者永远不知道模型真正需要什么信息。

你觉得"不必要"的字段,可能恰恰是模型做出正确判断的关键线索。你觉得"太长了"的原始日志,可能包含着一个只有模型才能识别出来的异常模式。

解决方案:MCP — 让模型直接"看"到世界

Model Context Protocol(MCP)是 Anthropic 在 2024 年底推出的开源协议。到 2026 年 3 月,它的 SDK 月下载量已经超过 9700 万次。

MCP 做的事情很简单:

给模型提供一个标准化的接口,让它直接访问外部系统的原始数据——而不是经过开发者预处理的数据。

Anthropic 自己管它叫"AI 的 USB-C 接口"。

以前的做法:

用户提问 → 你的代码读取文件 → 你的代码提取关键信息 
→ 你的代码组装 prompt → 模型看到你筛选过的信息

MCP 的做法:

用户提问 → 模型通过 MCP 直接读取文件 
→ 模型看到原始信息 → 模型自己判断什么重要

中间那层"人工翻译",消失了。

这意味着模型获得的不再是开发者认为重要的信息,而是原始的、完整的、未经裁剪的上下文

而且 MCP 不只是连接工具。它正在演化成一个上下文工程(Context Engineering)的基础设施——

Anthropic 最近在反复强调一个观点:

“Prompt Engineering 的时代已经过去了。我们进入的是 Context Engineering 的时代。”

什么是 Context Engineering?

就是不再只关注"你对模型说了什么",而是系统性地设计**“模型在思考的时候,能看到什么”**。

这包括:

  • 系统指令(你是谁,你的规则是什么)
  • 工具描述(你能做什么)
  • 外部数据(你能看到什么)
  • 对话历史(你之前经历了什么)
  • 精炼知识(你应该记住什么)

MCP 负责的,就是让这五层信息以标准化、无损的方式,流入模型的上下文窗口。

📌 落地资源:Model Context Protocol (MCP)

Anthropic 开源的连接协议。已被 Claude、Cursor、VS Code 等主流工具原生支持。

不是一个框架,而是一个协议——它定义的是"模型和世界之间应该怎么对话"。

官方文档:modelcontextprotocol.io


05 四条可以立刻用在代码里的原则

框架和项目说完了。但我知道,很多人看完还是会问:

“我现在没有精力重构整个架构,有没有什么小改动,今天就能生效的?”

有。四条原则,从小到大。

原则一:延迟结构化(Late Structuring)

旧做法: 在流程的第一步就让模型输出 JSON。后续所有节点都只操作这个 JSON。

新做法: 让模型在中间过程里用自然语言思考。只在最后一步——需要入库、调 API、返回前端的那一刻——才强制输出结构化数据。

OpenAI 的 Agents SDK 已经原生支持这个模式:中间步骤自由推理,只在最终输出时通过 output_type 参数强制 schema 校验。

在一切可以保持自然语言的地方,绝不使用 JSON。

这一条,可能是信噪比最高的改动。

原则二:传草稿,不传结论

当 Agent 调用工具失败时,不要只传 {"error": "timeout"}

把工具的原始报错信息、上一步的完整意图、甚至这是"第几次重试"的上下文,原封不动地拼接进对话历史。

模型非常擅长从"不完美"的上下文中恢复语义。但前提是你没有帮它做 summary。

你越替它总结,它就越"蠢"。
你越给它原始素材,它就越"聪明"。

这听起来反直觉,但真正用过 Coding Agent 长时间工作的人应该深有体会。

原则三:用 System Prompt 代替 If-Else

不要在代码里写:

if user_emotion == "angry":
    response_style = "empathetic"

在 System Prompt 里写:

在回复之前,先在 <thought> 标签内分析用户话语中的
隐性情绪和真实诉求。然后根据你的分析,自然地调整
你的语气和回应方式。

前者把"理解情绪"变成了一个离散的分类任务。
后者把"理解情绪"留在了模型连续推理的过程里。

语义的连续性,就是在这些微小的设计选择中被保护或者被摧毁的。

原则四:给 Agent 一个"锚"

在长对话或多步任务中,每隔几轮,让模型自己用自然语言重述一遍:“我现在在做什么,我为什么在做这个,接下来我打算做什么。”

这不是给人看的 log。

这是给模型自己的"锚点"——防止它在漫长的上下文里漂流太远。

业内管这叫思维链锚点(CoT Anchor)

简单到只需要在 System Prompt 末尾加一句话:

每完成一个阶段性步骤后,先用一句话总结当前进展和下一步计划,
再继续执行。

但效果是显著的。尤其在超过 20 个 tool call 的长链路任务里,它能把 Agent 的"目标漂移率"降低一半以上。


06 一个完整的落地清单

如果你正在做 Agent 产品,下面是一份你可以对照检查的清单:

控制流层 ✅

检查项 传统做法 语义连续做法
意图路由 代码 if-else 分发 模型自主决策 + Handoff
多步任务 代码编排 Workflow 模型内部推理链
错误处理 代码捕获 + 重试 原始错误传入上下文
子任务协作 JSON 接口传参 完整对话历史传递

记忆层 ✅

检查项 传统做法 语义连续做法
历史存储 向量切片 分层记忆(短期/长期/情景)
信息更新 覆盖旧记忆 ADD-Only 追加
检索方式 单一向量搜索 多信号融合(向量+关键词+实体)
记忆管理 开发者手动设计 Agent 自主管理

传输层 ✅

检查项 传统做法 语义连续做法
外部数据接入 代码预处理后传入 MCP 直连原始数据
工具描述 硬编码 schema 按需动态发现
上下文管理 被动堆积 主动裁剪 + 分层注入

07 写在最后

其实回头看,这篇文章想说的核心就一件事:

语义连续性不是一种玄学,而是一种工程选择。

每一个 if-else,每一次 JSON.stringify(),每一刀 summary——你都在做一个选择:是保留语义的完整性,还是为了工程的确定性而牺牲它。

以前我们没得选。模型太弱,上下文窗口太小,你不切就装不下。

但 2026 年了。上下文窗口动辄 100K、200K。模型的推理能力已经足够强。

是时候把那些"不得已的妥协"还回去了。

不瞒你说,我自己重构 Agent 项目的时候,最大的阻力不是技术——而是心理。

你会本能地想控制一切。你会觉得"不用 if-else 我怎么保证流程正确"。你会担心"不做 summary 上下文会不会爆掉"。

但当你真正放手,让模型在一段完整的、未被切割的语义里自由游泳的时候——

你会发现它回复的质量,突然就不一样了。

不是更"正确"。
是更"懂"了。

那种感觉,就像你跟一个人聊天,他第一次真正听懂了你在说什么。

不是因为他更聪明了。

而是因为——你终于没再打断他。


精选金句:

  • 语义在进入 if-else 的那一瞬间,就从一段连续的理解,变成了一个离散的标签
  • 向量数据库存储了语义的碎片,但丢失了语义的连续性
  • 你越替它总结,它就越"蠢"。你越给它原始素材,它就越"聪明"
  • 在一切可以保持自然语言的地方,绝不使用 JSON
  • 语义连续性不是一种玄学,而是一种工程选择

本文提及的项目与资源汇总:

资源 解决什么 链接
OpenAI Agents SDK 控制流层:对话即控制流 github.com/openai/openai-agents-python
Mem0 记忆层:多信号融合记忆 github.com/mem0ai/mem0
Letta 记忆层:OS 式分层记忆 github.com/letta-ai/letta
MCP 传输层:模型直连外部数据 modelcontextprotocol.io
Anthropic Context Engineering 方法论:上下文工程指南 anthropic.com

上一篇:[我终于意识到:AI 产品真正的单位不是 Function,而是语义连续性]

如果这篇对你有用,转发给你团队里正在做 Agent 的工程师。他可能正在某个 if-else 里,把语义切碎。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐