Agent 工程:Langchain & Long Horizon Agent
本文是对 Langchain 前不久分享的 Long Horizon Agent 的详细解读。
长周期任务(Long-horizon Task)。
简单说,就是让 Agent 干点大事儿,不是那种问个问题就完事儿的客服,而是能独立思考、规划、执行一整套复杂流程的“数字员工”。比如让它独立完成一个软件开发项目,或者做一份完整的市场分析报告。
配图:Bytedance-Seeddream 4.0
一、从“单核”到“多核自主”
我们程序中的代码怎么写,程序就怎么跑,一切都是确定性的。就算有并发,那也是在可控的逻辑之内。
1.1 传统 LLM 应用
最早的 LLM 应用,比如做一个简单的问答机器人,本质上还是传统软件的思路。
你可以把它想象成调用一个特别牛逼的函数。
整个流程是线性的、确定的:
- 输入(Input): 用户提个问题。
- 构建提示词(Prompt): 你的代码把用户问题,加上你预设的模板、可能还有 RAG 检索出来的知识,打包成一个 Prompt。
- 调用 LLM: 把这个 Prompt 扔给大模型。
- 输出(Output): 大模型返回结果,你的代码再处理一下,展示给用户。
这个过程里,核心逻辑掌握在咱们开发者手里。哪个环节出了问题,比如回答不理想,我们很清楚是 Prompt 构造得不好,还是 RAG 检索的数据不对。因为输入 LLM 的 context 是由我们的代码完全决定的,所以调试起来思路很清晰,无非就是加 print、打断点、看日志。
1.2 Long Hoizon Agent 应用
但 Long Hoizon Agent 就不一样了。它不再是简单地被调用一次,而是在一个循环(Loop)里自主运行。
这个模式,我们可以叫它 ReAct 框架(Reasoning and Acting,思考与行动)。
Agent 的每一步都是这样的循环:
- 思考(Thought): 基于当前的目标和历史信息,LLM 先自己琢磨一下,“下一步我该干啥?”
- 行动(Action): 决定调用哪个工具(比如访问网页、执行代码、查询数据库)以及用什么参数。
- 观察(Observation): 执行工具后,得到一个结果。
- 再次思考: 把这个结果作为新的信息,放进下一轮的“思考”里,如此往复,直到完成最终目标。
看出问题了没?Agent 的执行路径是动态生成的,充满了不确定性。
举个例子,你让 Agent 写个爬虫。在第 1 步,它可能决定先搜索一下目标网站的结构。在第 2 步,它根据搜索结果,决定写一段 Python 代码来爬取。但如果第 2 步代码执行报错了,它在第 3 步可能就会决定去 Google 搜索这个错误,而不是继续写代码。
这意味着,在 Agent 启动之前,你根本无法预测它在第 14 步会干什么,以及那时候喂给 LLM 的 context 会是什么样。因为这取决于前面 13 步执行的结果,而每一步都可能从外部环境(比如网页、数据库)引入任意的新信息。
这就引出了一个核心概念,也是构建 Agent 的精髓所在:上下文工程(Context Engineering)。
上下文工程 (Context Engineering) 是一个很精妙的词,它涵盖了所有为 LLM 提供和管理上下文信息的技术。这不仅仅是写个好 Prompt,它包括:如何动态地从外部数据源(如数据库、API、文件)检索信息、如何维护对话历史(记忆)、如何选择并格式化工具的输出,然后把所有这些信息以一种 LLM 能理解的方式,塞进那个小小的上下文窗口里。
在 Agent 的世界里,一切都是上下文工程。 你的工作不再是编写死的业务逻辑,而是设计一套机制,让 Agent 能够自己有效地构建和管理上下文,从而引导 LLM 做出正确的“思考”和“行动”。
1.3 长周期 & Harness
Harrison 在访谈里提到了一个非常深刻的观点:在 Agent 运行之前,你根本无法预测它在第 14 步会干什么。
咱们写后端代码,讲究幂等性,讲究可预测。但在 Agent 里:
- 第 1 步,它决定搜一下 Google。
- 第 2 步,它根据 Google 的结果(这个结果是动态的),决定写一段 Python 代码。
- 第 3 步,代码报错了(这也是动态的)。
- ...
- 第 14 步,它此刻面临的 Context,是由前面 13 步所有不可控的外部环境反馈堆积起来的。
这就叫 Long-horizon(长周期/长程)。任务战线拉得越长,不确定性累积得越多。前面的任何一个小偏差,都可能导致第 14 步的大模型“发疯”或者陷入死循环。
所以,开发 Agent 的核心难点,不在于模型本身(那是 OpenAI 的事),而在于如何设计这个循环的“笼子”,让模型在长周期的“长跑”中,既能自由发挥,又不至于跑偏。
这个“笼子”,就是我们要讲的下一个核心概念——Harness(挽具/特制框架)。
LangChain 是一个 Framework(框架)。框架的特点是通用、灵活、不设限,它给你提供螺丝刀和扳手,你想造自行车还是造火箭随意。
但 Harness(挽具) 不一样。这词儿本来是指套在马身上的器具,用来控制马车的。在 Agent 领域,Harness 是指一种高度定制化、opinionated(有主解/固执)的架构设计。
为什么需要 Harness? 因为通用的 ReAct 循环太容易发散了。如果你要做一个“写代码的 Agent”,你不能只给它一个通用的循环。你需要给它设计一套专门的流程:
- 强制它先读文件结构。
- 强制它先写测试用例。
- 强制它在修改代码前进行 plan。
- 限制它只能访问特定的目录。
这就是 Harness。Harness = 针对特定任务固化的工作流 + 专用的工具集 + 记忆管理策略。
目前市面上最成功的 Agent,比如 Devin、OpenAI 的 Deep Research,本质上都不是靠模型通杀,而是靠精心设计的 Harness。这个 Harness 里包含了无数的 if-else 逻辑(没错,还是咱们后端那一套),用来处理模型可能出现的各种边缘情况。
二、软件开发 vs. Agent 开发
既然 Agent 的核心逻辑一部分在我们的代码里,另一部分在 LLM 这个“黑盒”里,那我们开发和维护它的方式也必须跟着变。
传统的软件开发流程,我们称之为 Software 1.0,核心是“代码即逻辑”。而 Agent 开发,则进入了 Software 2.0/3.0 的范畴,其核心是“数据/模型即逻辑”。
这种转变带来的最大不同,体现在调试、测试和迭代这几个关键环节。
2.1 调试:从“断点”到“轨迹”
在 Software 1.0 的世界里,遇到 Bug,我们的第一反应是祭出 Debugger,打个断点,看看变量、走走堆栈,问题基本就定位了。因为代码是确定的,只要输入一样,执行路径就一样。
但在 Agent 的世界里,这套不灵了。
Agent 的行为是非确定性的,你这次运行出错了,下次用同样的输入再跑一遍,它可能因为某个外部 API 返回了稍微不同的结果,就走了另一条路,那个 Bug 就不复现了。你上哪儿打断点去?
而且,很多时候问题不是出在你的代码(Harness/框架)上,而是 LLM 的“思考”跑偏了。比如,它明明应该调用 A 工具,却错误地理解了当前情况,决定去调用 B 工具。这是代码层面的 Bug 吗?不是。这是模型的决策失误。
所以,调试 Agent 的核心,不再是看代码的执行,而是理解 Agent 的决策过程。我们需要一个工具,能把 Agent 的每一次“思考 -> 行动 -> 观察”循环都记录下来,形成一个完整的执行轨迹(Trace)。
这个 Trace 就是 Agent 的“行车记录仪”。通过回放 Trace,我们可以清晰地看到:
- 在每一步,Agent 拿到了什么信息(上下文)?
- 基于这些信息,它做了什么“思考”(Reasoning)?
- 它决定调用哪个“工具”(Action)?
- 工具返回了什么“结果”(Observation)?
对于 Agent 开发来说,Trace 就是最重要的调试工具,没有之一。 它把 LLM 的黑盒决策过程给透明化了。当我们发现 Agent 最终结果不对时,就可以顺着 Trace 往回看,到底是哪一步的决策出了问题,以及为什么会出问题(是上下文信息不足?还是 Prompt 引导有误?)。
2.2 测试:从“单元测试”到“评估”
传统软件的测试相对简单。我们可以写大量的单元测试(Unit Test),给一个函数确定的输入,然后断言(Assert)它必须返回确定的输出。
但 Agent 怎么写单元测试?它的输出本身就是不确定的。你让它“总结一下这篇文章”,它两次总结出来的措辞几乎不可能完全一样。你怎么断言?
因此,Agent 的测试范式也从确定性的断言转向了基于评估(Evaluation)的测试。
这个过程通常是这样的:
- 构建评估数据集: 你需要准备一批有代表性的输入样本(比如,100 个不同的用户请求),以及它们对应的“理想”输出(或者说,判断标准)。
- 批量运行 Agent: 让你的 Agent 处理这 100 个样本。
- 进行评估: 对每一个输出结果进行打分。
这里的关键是“打分”。怎么打?有两种主流方式:
- 人工评估: 这是最靠谱的方式。找个产品经理或者你自己,挨个去看 Agent 的输出,判断它做得好不好(比如,“这个总结抓住了重点吗?”“这个代码能运行吗?”)。这在 LangSmith 这类平台上,就是给 Trace 打上“好”或“坏”的标签。
- AI 评估(LLM-as-Judge): 当你有大量样本需要评估时,人工太慢了。这时可以再找一个更强大的 LLM(比如 GPT-4o)来当“考官”。你给考官一个评分标准(比如,从相关性、准确性、简洁性几个维度打分),让它来给“考生”Agent 的答案打分。
评估(Eval)是 Agent 开发的核心迭代工具。 通过对一批 Trace 进行评估,你就能得到一个量化的性能指标(比如,在测试集上的准确率是 85%)。当你修改了 Agent 的 Prompt 或者工具后,再跑一遍评估,如果准确率提升到了 90%,就说明你的修改是有效的。
2.3 迭代:从“编码-编译”到“上下文-评估”
综合调试和测试的变化,整个 Agent 的开发迭代循环也完全不同了。
传统软件开发的循环是:写代码 -> 编译/运行 -> 跑单元测试 -> 发现 Bug -> 回去改代码。
Agent 开发的循环则是:调整上下文(Prompt/工具/RAG)-> 运行 Agent 收集 Trace -> 评估 Trace(人工或 AI)-> 发现 bad case -> 回去调整上下文。
你看,在这个新循环里,纯粹的编码工作(搭建 Harness)的比重下降了,大量的时间被花在了与“上下文”相关的调试和迭代上。你的日常工作可能变成了:
- “我发现有 10% 的 Trace 都失败了,我去看看这些失败案例的共同点。”
- “哦,原来是 Agent 在处理 JSON 格式时总会犯错,我得去优化一下 Prompt,给它一个处理 JSON 的示例。”
- “我给 Agent 新增了一个
get_weather工具,现在得去评估集里加几个和天气相关的测试用例。”
这个新的开发流程,对我们后端开发者提出了全新的要求。我们不仅要会写稳健的代码来搭建 Agent 框架,更要学会如何像一个产品经理或数据科学家一样,去“训练”和“驯化”一个 Agent。这更像是在带一个天赋异禀但有点不听话的实习生,你需要不断地给他提供高质量的案例(评估数据)和清晰的指导(Prompt),并通过复盘他的工作(Trace)来修正他的行为,而不是像以前一样,对着一台完全听话的、精确的机器发号施令。
三、深入 Agent 架构的核心组件
要构建一个能干活的 Agent,光有 ReAct 循环还不够,我们需要一套完整的“装备”。这个“装备”就是我们之前提到的 Harness,它通常由几个核心组件构成。
3.1 Executor
这是 Agent 的“心脏”,一个负责驱动 ReAct 循环的核心逻辑。它的工作很简单但至关重要:
- 把当前的上下文(目标、记忆、工具列表)打包成 Prompt 发给 LLM。
- 接收 LLM 返回的包含“思考”和“行动”的文本。
- 解析这段文本,识别出需要调用的工具和参数。
- 调用工具,获取结果。
- 把结果再塞回上下文,准备下一次循环。
如何精确地解析 LLM 的输出是这里的技术难点之一。早期的 Agent 依赖正则表达式,非常脆弱。现在,主流模型都支持函数调用(Function Calling)或工具使用(Tool Use)功能,LLM 可以直接返回结构化的 JSON,大大提升了执行的稳定性和可靠性。
3.2 Tools
如果说 LLM 是 Agent 的“大脑”,那么工具就是 Agent 的“手和脚”。工具是 Agent 与外部世界交互的唯一桥梁,也是将其能力从“能说会道”升级到“能干实事”的关键。
工具的本质就是我们开发者暴露给 Agent 的函数。这些函数可以是:
- 通用工具: 比如网络搜索、代码执行器、计算器。
- 业务 API: 比如查询公司内部的 CRM 系统、调用支付接口、读取 Jira 的任务列表。
- 数据接口: 比如查询数据库、读取本地文件。
设计一个好的工具,关键在于为它编写一个清晰、详尽的描述(description)。这个描述就是你和 LLM 之间的“API 文档”。你需要用自然语言告诉 LLM:这个工具是干什么用的?它接收什么参数?每个参数是什么意思?比如:
@tool
def search_flights(origin: str, destination: str, date: str) -> List[Flight]:
"""
Searches for available flights.
:param origin: The departure airport code, e.g., "SFO".
:param destination: The arrival airport code, e.g., "JFK".
:param date: The flight date in "YYYY-MM-DD" format.
"""
# ... a bunch of code to call flight APIs ...
return flights
这个 docstring 比代码本身更重要,因为 LLM 就是靠它来理解何时以及如何使用这个工具的。
3.3 Memory
对于需要执行多步的长周期任务,记忆是必不可少的。Agent 需要记住历史对话、过去的行动和结果,甚至是从失败中总结的经验,以避免重复犯错并做出更长远的规划。
记忆系统面临的最大挑战就是上下文窗口的限制。现代 LLM 的上下文窗口虽然越来越大(从几千 token 到上百万 token),但终究是有限的。当交互历史变得很长时,你不可能把从创世以来的所有对话都塞进 Prompt 里,这既昂贵又低效。
3.3.1 记忆压缩
记忆压缩(Compaction)。
我们有多种策略来管理记忆:
- 滑动窗口(Sliding Window): 最简单粗暴的方法,只保留最近的 K 轮对话。优点是简单,缺点是容易丢失早期的重要信息。
- 摘要(Summarization): 当历史对话超长时,用另一次 LLM 调用来把前面的对话内容总结成一段摘要。这样,上下文就变成了“历史摘要 + 最近几轮对话”。
- 向量化检索(Vector-based Retrieval): 这是更高级也更常用的方法。将每一轮对话或每一个重要的观察结果,都用 Embedding 模型转换成向量,存入向量数据库。在每一步决策前,Agent 先将当前的目标或问题也转换成向量,然后去数据库里检索最相似、最相关的“记忆片段”,只把这些片段放入上下文中。这本质上就是给 Agent 的“私有记忆”做了一个 RAG 系统。
一个设计良好的记忆系统,是 Agent 能否处理长周期任务的关键。
3.3.2 文件系统作为上下文
Filesystem as Context,这是 Harrison 非常推崇的一个点。对于 Coding Agent 或者 Research Agent,文件系统不仅是工具,更是最完美的上下文存储器。
为什么?因为代码文件、Markdown 笔记,本身就是结构化的。
- Agent 把思考结果写进
plan.md。 - Agent 把代码写进
main.py。 - Agent 把报错记录写进
error.log。
在下一轮循环开始时,我们只需要把这些文件的内容重新读出来喂给 LLM。这样,文件系统就变成了 Agent 的“外挂硬盘”。这种方式比纯粹的 Chat History 要稳定得多,因为它是显式的、持久化的。
3.4 Planning & Reflection
对于真正复杂的、需要几十上百步才能完成的任务,光靠一步一步的 ReAct 循环可能还不够。Agent 可能会“只见树木,不见森林”,陷入某个局部最优解或者干脆迷失方向。
因此,更高级的 Agent 架构引入了规划**(Planning)和反思(Reflection)**的机制,让 Agent 具备更高层次的认知能力。
- 规划: 在任务正式开始执行前,先让 LLM 生成一个高层次的计划。比如,“要完成‘开发一个网站’这个任务,我需要分三步:1. 创建项目结构;2. 编写前端代码;3. 编写后端代码。” 然后,Agent 严格按照这个计划去执行。每完成一步,它再来更新或细化接下来的计划。这种分而治之的策略,大大提高了任务的成功率。
- 反思: 当 Agent 执行完一系列操作后,或者在某个步骤卡住、反复出错时,让它停下来,回顾一下自己的整个执行轨迹(Trace),然后进行自我总结和批评:“我刚才尝试调用 API 失败了,错误是 401 Unauthorized。这说明我的 API 密钥可能是错的。下次我应该先检查一下密钥的有效性。” 这种宝贵的反思结果,可以被存入记忆系统,作为未来的经验,从而实现真正的自我提升(Self-Improvement)。
这种“计划-执行-反思”的循环,让 Agent 的行为模式更接近一个真正的人类专家,而不是一个只会低头走路的简单执行器。
四、我的看法
- Agent 开发的本质是“人机协同”的新范式。 别指望现在就能一步到位,做出一个完全自主、100% 可靠、能处理任何事情的通用 Agent。那还为时过早。现实中,我看到的、最有价值的 Agent 应用,都是“人机协作”模式。Agent 负责完成 80% 的繁琐、重复性的工作,生成一个“初稿”(First Draft),然后由人类专家来做最后 20% 的审核、修正和决策。无论是写代码(Agent 生成 PR,工程师 Code Review),还是做市场研究(Agent 搜集资料写报告,分析师提炼最终洞见),都是这个路子。把 Agent 当成一个能力超强、不知疲倦但偶尔会犯傻的实习生,而不是一个全能的上帝,你的心态上会踏实很多。
- “可观测性”是 Agent 应用落地的命脉。 既然 Agent 的行为难以预测和复现,那么能够记录、可视化和分析它的每一次行为(也就是 Trace),就成了绝对的刚需。没有好的可观测性工具,调试和迭代 Agent 就像在摸黑开锁,你根本不知道问题出在哪,只能靠反复尝试和一点玄学。这也是为什么 LangChain 会把 LangSmith 作为其商业化的核心。对于任何想严肃地把 Agent 应用于生产环境的公司来说,搭建好自己的观测和评估体系,是比研究那些花里胡哨的 Agent 算法更优先、更基础的工作。
- Harness > Model。 在可预见的未来,顶级的 Foundation Model 能力会趋于同质化。真正的竞争壁垒不在于你用的是 GPT-5 还是 Claude 4,而在于你围绕模型构建的那个独特的 Harness(框架/工具集)。你为你的 Agent 提供了哪些别人没有的、与你业务深度绑定的工具(私有 API)?你积累了多少高质量的、针对你业务场景的评估数据集(Evals)?你设计的记忆和反思机制是否足够高效?这些与业务深度绑定的“上下文工程”能力,才是构建应用护城河的关键。别再天天只盯着模型本身了,多想想怎么把你自己的业务数据和流程,变成 Agent 能用的“弹药”。
- 最终,所有强大的 Agent 都将是“代码 Agent”。 思考一下,无论是浏览网页、分析数据、操作软件,还是管理云资源,这些任务的底层操作很多都可以被归结为执行一小段代码或脚本。代码是与计算机交互最精确、最强大、最通用的语言。因此,一个自带 Code Sandbox 的 Agent,拥有近乎图灵完备的能力。我认为,未来最强大的通用 Agent,其核心能力之一必然是能够熟练地生成和执行代码,将非结构化的自然语言目标,转化为结构化的、可验证的程序执行。
0