【学习笔记】框架层坍缩——LangChain 们正在被重新定义-14/15

2023 年,用 LangChain 构建一个 Agent 需要写大量「脚手架」代码:

  • 路由逻辑:判断用户意图,决定调哪个 Chain
  • 工具选择:根据任务类型选择合适的工具
  • 输出解析:用 OutputParser 把模型的文本输出转成结构化数据
  • 重试逻辑:模型返回格式错误时自动重试
  • 提示模板:用 PromptTemplate 管理复杂的 Prompt 拼接

这些功能,LangChain 都提供了封装好的抽象。

2026 年,如果你用 Claude 3.7 或 GPT-4o 直接调用 API,大多数情况下不需要这些封装------模型自己就会做。

这就是框架层坍缩


一、什么是框架层坍缩

「坍缩」不是说框架消亡了。是说框架过去承担的功能,正在被转移到两个方向:

一部分向下转移到模型层------模型变聪明了,以前需要代码来实现的逻辑,现在模型原生就能做。

一部分向上转移到 Harness 层------真正属于系统工程的部分,从框架里分离出来,成为独立的 Harness 关注点。

中间那层「框架胶水代码」正在萎缩。


二、已被模型吸收的功能(约 80%)

2.1 路由决策

2023 年的做法:写一个 Router Chain,根据用户意图的关键词或分类模型,决定把请求路由到哪个处理链。

2026 年的做法:直接告诉模型有哪些能力,让它自己决定用哪个:

复制代码
# 2023 年:需要显式路由逻辑
from langchain.chains.router import MultiPromptChain

chains = {
    "coding": coding_chain,
    "writing": writing_chain,
    "analysis": analysis_chain,
}
router = MultiPromptChain(router_chain=..., destination_chains=chains)
result = router.run(user_input)

# 2026 年:模型自己路由
response = client.messages.create(
    model="claude-opus-4-7",
    system="""你有以下能力:
- 代码编写和审查(写代码、debug、代码解释)
- 文档写作(技术文档、说明书、报告)
- 数据分析(统计、可视化建议、洞察)

根据用户请求,选择合适的能力完成任务。""",
    messages=[{"role": "user", "content": user_input}]
)
# 模型自己判断该做什么,不需要路由逻辑

2.2 工具选择

以前需要手动实现工具选择逻辑,或者用框架的 Agent Executor 来管理工具调用顺序。

现在模型的 Function Calling / Tool Use 原生支持工具选择------给模型一组工具,它自己决定调哪个、什么时候调、调几次:

复制代码
tools = [
    {
        "name": "read_file",
        "description": "读取文件内容",
        "input_schema": {"type": "object", "properties": {"path": {"type": "string"}}}
    },
    {
        "name": "search_web",
        "description": "搜索网络信息",
        "input_schema": {"type": "object", "properties": {"query": {"type": "string"}}}
    },
    {
        "name": "run_code",
        "description": "执行 Python 代码",
        "input_schema": {"type": "object", "properties": {"code": {"type": "string"}}}
    }
]

# 模型自己决定用哪个工具、按什么顺序
response = client.messages.create(
    model="claude-opus-4-7",
    tools=tools,
    messages=[{"role": "user", "content": "分析 data.csv 里的销售趋势"}]
)
# 模型会先 read_file("data.csv"),然后 run_code 做分析
# 不需要任何手动编排逻辑

2.3 输出解析

以前需要 OutputParser 把 "Answer: 42" 这样的文本提取出 42,或者把 Markdown 表格转成 Python 字典。

现在模型原生支持结构化输出:

复制代码
import anthropic
from pydantic import BaseModel

class CodeReviewResult(BaseModel):
    passed: bool
    issues: list[str]
    severity: str
    suggestions: list[str]

# Claude 直接输出符合 schema 的 JSON,不需要解析
response = client.messages.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": f"审查以下代码:\n{code}"}],
    tools=[{
        "name": "submit_review",
        "description": "提交代码审查结果",
        "input_schema": CodeReviewResult.model_json_schema()
    }],
    tool_choice={"type": "tool", "name": "submit_review"}  # 强制调用这个工具输出结构化结果
)

# 直接得到结构化结果,无需解析
result = CodeReviewResult(**response.content[0].input)

2.4 重试逻辑

以前当模型输出格式不对,需要手写 retry 循环,或者用框架的 RetryParser。

现在模型更可靠,格式错误率大幅下降;即使出错,可以直接在对话里纠正:

复制代码
def get_structured_output(prompt: str, schema: type) -> dict:
    messages = [{"role": "user", "content": prompt}]
    
    for attempt in range(3):  # 最多 3 次,通常第一次就对
        response = client.messages.create(
            model="claude-sonnet-4-6",
            messages=messages,
            tools=[{"name": "output", "input_schema": schema.model_json_schema()}],
            tool_choice={"type": "tool", "name": "output"}
        )
        
        try:
            return schema(**response.content[0].input)
        except Exception as e:
            # 把错误反馈给模型,让它自己修正
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": f"输出格式有误:{e},请重新输出"})
    
    raise RuntimeError("多次尝试后仍无法获得正确格式")

三、仍在 Harness 层的部分(约 20%)

模型变聪明可以替代很多胶水代码,但有四类问题,再聪明的模型也解决不了------这些是 Harness 不可替代的部分。

3.1 持久化

模型没有持久记忆。对话结束,上下文消失。跨会话的状态------任务进度、用户偏好、项目背景------必须由 Harness 管理:

  • 文件系统CLAUDE.mdAGENTS.md、progress.txt------人类可读的持久化
  • 数据库:结构化状态、用户数据、任务历史
  • Git:代码变更的版本控制,也是 Agent 操作的审计日志

这不会被模型替代。模型可以读写文件,但决定「什么状态需要持久化、怎么组织、何时清理」是 Harness 设计问题。

3.2 确定性重放

模型是概率性的,同样的输入可能产生不同的输出。对于需要「从断点恢复」的长程任务,必须有确定性的检查点机制:

  • 每完成一个关键步骤,把状态写入检查点
  • 任务失败时,从最近的检查点重启,而不是从头来
  • 人工审查时,能精确复现某次执行的完整路径

LangGraph 的 Checkpoint 机制是目前这类需求最成熟的解决方案。这不是模型能力问题,是工程基础设施问题。

3.3 可观测性

上一篇讲了 Agent 可观测性------Traces、Metrics、Logs。这些不是模型能力,是系统基础设施:

  • 模型不能给自己追踪 Token 用量
  • 模型不知道自己这次调用花了多少钱
  • 模型不能在失败时自动报警

这些是 Harness 层的职责,无论模型多聪明都不会改变。

3.4 错误恢复

有一类错误是模型层面无法处理的------基础设施错误

  • API 限流(429 Too Many Requests)
  • 网络超时
  • OOM(内存溢出)
  • 依赖服务宕机

处理这类错误需要 Harness 层的重试策略、断路器、降级方案。模型不知道外部世界发生了什么,它只能生成 token。

复制代码
import anthropic
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(5),
    wait=wait_exponential(multiplier=1, min=4, max=60),
    retry=lambda exc: isinstance(exc, (anthropic.RateLimitError, anthropic.APITimeoutError))
)
def call_with_retry(messages: list) -> str:
    """Harness 层处理基础设施错误,模型层不感知"""
    response = client.messages.create(
        model="claude-opus-4-7",
        max_tokens=4096,
        messages=messages
    )
    return response.content[0].text

四、Framework vs Harness 的本质区别

理解了什么被吸收、什么留下来,就能看清楚 Framework 和 Harness 的本质区别:

Framework 解决的是「开发者如何构建 Agent」的问题------抽象、封装、减少样板代码。当模型变强,开发者需要的抽象减少,框架的价值自然下降。

Harness 解决的是「Agent 如何在生产中安全运行」的问题------持久化、可观测性、故障隔离、成本控制。这些不随模型能力变化而消失,生产系统永远需要这些。

这两件事的目标受众不同:Framework 服务开发者,Harness 服务运行中的 Agent。


五、各框架的进化方向

既然框架层在坍缩,各框架是怎么应对的?

5.1 LangChain → LangGraph

LangChain 最初的定位是「AI 应用开发框架」,提供大量封装好的 Chain、Agent、Memory 抽象。随着模型能力增强,这些抽象的必要性下降。

LangChain 的应对:把重心转移到 LangGraph------专注于工作流编排(状态机、检查点、持久化),而不是封装模型调用。

这个转型方向对:LangGraph 提供的正是「仍在 Harness 层」的那部分功能,不会被模型替代。

5.2 CrewAI → 企业级 Harness

CrewAI 从角色编排框架演进,正在向企业级 Harness 平台发展------加入更多生产特性:任务追踪、成本监控、企业权限管理、合规报告。

这个方向也对:把框架定位从「帮你写 Agent」变成「帮你在生产中跑 Agent」。

5.3 AutoGen → MAF(微软统一框架)

Microsoft 把 AutoGen 和 Semantic Kernel 合并,构建 MAF(Microsoft Agent Framework)------不再只是对话式多 Agent,而是覆盖从 Agent 开发到企业级部署的完整栈。


六、轻量 Harness 方法:把规则写进提示

框架层坍缩还催生了一种新的 Harness 模式:Markdown-based Harness------把 Harness 规则直接写进系统提示或配置文件,而不是用代码实现。

6.1 AGENTS.md 模式(Codex 推广的约定):在项目根目录放一个 AGENTS.md 文件,Agent 在开始任务前自动读取:

复制代码
# AGENTS.md

## 工作约束
- 修改代码前先运行测试,确认当前基线通过
- 每完成一个子任务,git commit 一次,commit message 格式:feat/fix/refactor: 简短描述
- 不要修改 .env 和 credentials/ 目录下的任何文件
- 如果不确定,停下来问,不要猜

## 代码规范
- Python 3.11+,使用 type hints
- 单行不超过 88 字符(black 格式化标准)
- 所有公共函数必须有 docstring

## 测试要求
- 修改任何功能代码后,新增或更新对应测试
- 运行命令:pytest tests/ -v --tb=short
- 覆盖率目标:核心模块 90%+

## 禁止操作
- 不执行 DROP TABLE, DELETE FROM(无 WHERE 条件)
- 不 push 到 main 分支,只能提 PR
- 不在代码里硬编码 API key 或密码

6.2 CLAUDE.md 模式(Claude Code 的约定):项目级别的持久化记忆和约束,Claude Code 在每个会话开始时自动读取。

这种方法的优势:

  • 零框架依赖:只是一个文件,任何 Agent 都能读
  • 人类可读可编辑:不需要改代码就能调整 Agent 行为
  • 版本控制友好:和代码一起提交,有完整的修改历史

限制:只能表达「静态规则」,动态的流程控制(条件分支、循环、检查点)仍然需要代码。


七、什么时候用框架,什么时候不用

有了前面的分析,可以给出一个实用的决策框架:

7.1 不需要框架的场景

  • 单次 LLM 调用,即使很复杂
  • 简单的工具调用序列,不需要复杂编排
  • 原型验证阶段,快速实验想法

这些场景直接用 SDK 就好------anthropic.messages.create(),干净、可控、没有额外依赖。

7.2 需要 LangGraph 的场景

  • 工作流有复杂的条件分支(成功/失败走不同路径)
  • 需要跨会话的检查点和状态恢复
  • 有人工审批节点的长程任务

7.3 需要 CrewAI 的场景

  • 明确的角色分工(代码生成 + 测试 + 审查)
  • 需要快速上手多 Agent 编排
  • 已有 CrewAI 技术栈的团队

7.4 不需要任何框架,但需要 Harness 的场景

  • 生产部署:可观测性、成本监控、错误恢复------这些用基础设施工具(Langfuse、Helicone),不需要 Agent 框架
  • 长程任务:自己实现检查点,不一定要上 LangGraph

八、反直觉的结论:更少的框架依赖,更好的 Harness

一个经常被忽视的事实:框架引入了依赖、学习成本、升级风险。

当 LangChain 从 0.x 升到 1.x,API 全面破坏性变更,依赖它的项目要花大量时间迁移。这不是批评 LangChain------任何快速演进的框架都会这样。

成熟的团队正在走向「最小框架依赖」的方向:

  • 直接用 Anthropic/OpenAI SDK
  • 只在真正需要时引入 LangGraph(状态机编排)
  • Harness 层用基础设施工具(不是框架):Langfuse 做可观测性,Helicone 做成本追踪

这不是反框架,是认清楚框架的边界------在它真正有价值的地方用它,在其他地方用更简单的方案。

复制代码
# 2026 年的「最小框架依赖」Agent 架构
import anthropic        # 直接用 SDK
from langfuse.decorators import observe  # 只引入可观测性工具

@observe()  # Harness:追踪
def run_agent(task: str) -> str:
    client = anthropic.Anthropic()
    messages = [{"role": "user", "content": task}]
    
    while True:
        response = client.messages.create(
            model="claude-opus-4-7",
            max_tokens=4096,
            tools=TOOLS,  # 工具列表
            messages=messages
        )
        
        if response.stop_reason == "end_turn":
            return response.content[0].text
        
        # 处理工具调用(模型自己决定用哪个工具)
        tool_results = execute_tool_calls(response.content)
        messages.append({"role": "assistant", "content": response.content})
        messages.append({"role": "user", "content": tool_results})
        
        # Harness:检查点(每次工具调用后保存状态)
        save_checkpoint(messages)

这段代码没有 LangChain,没有 CrewAI,没有 AutoGen,但它有 Harness:可观测性追踪、工具执行隔离、检查点保存。

这就是框架层坍缩之后,「真正的 Harness」长什么样。

参考文献:

框架层坍缩------LangChain 们正在被重新定义

相关推荐
大白菜和MySQL1 小时前
elk部署和kibana图形化展示
java·笔记·elasticsearch
梦想三三2 小时前
LangChain模型调用与多轮对话完整实战
阿里云·langchain·大模型·api
吃好睡好便好2 小时前
Creo中工作目录的设置
学习·creo·工作目录
极地野狼 音乐哔哔2 小时前
【机器人 / 强化学习】DIVL:分布隐式价值学习
学习·机器人
mapengfei2 小时前
LangChain学习背景
langchain·llm
pluviophile_s2 小时前
数据结构:第6讲:树与二叉树
数据结构·笔记
爱莉希雅&&&2 小时前
Rocky Linux 10.1 + K8s 1.36.3 离线集群部署笔记(Kubernetes)
linux·笔记·docker·kubernetes·calico
lichuangcsdn2 小时前
【Spring AI 学习(三)】实现简单的对话
java·人工智能·学习·spring·spring ai
星恒随风2 小时前
C++ 多态底层原理:静态绑定、动态绑定、虚函数表与工程实践
开发语言·c++·笔记·学习