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.md、AGENTS.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 们正在被重新定义