ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

从循环工程到Harness工程:构建生产级AI智能体的架构与实践

2026/8/22 20:44:21 拓冰建站 浏览量
从循环工程到Harness工程:构建生产级AI智能体的架构与实践 如果你正在构建一个AI智能体是否曾陷入这样的困境精心设计的Agent在演示时表现惊艳一旦投入实际业务却频繁“掉链子”——要么无法稳定执行多步任务要么在复杂环境中“失忆”或“跑偏”问题往往不在于模型本身而在于我们构建智能体的工程化方式。传统的“一次性提示工程”或简单的链式调用已经难以支撑生产级AI应用的需求。这正是“循环工程”与“Harness工程”这两个新兴概念正在试图解决的核心痛点。它们不是某个具体框架而是一套将AI智能体从“玩具”升级为“工具”的架构思想与工程实践。本文将深入拆解这两种工程范式并通过一个基于LangGraph的实战项目展示如何构建一个具备记忆、工具调用、状态管理和自我修正能力的生产级AI智能体系统。1. 这篇文章真正要解决的问题当前AI智能体开发存在一个显著的“演示陷阱”在精心设计的单一场景下智能体可以完美运行但一旦面对真实世界复杂、多变的业务流程其稳定性、可靠性和可维护性便急剧下降。开发者常常花费大量时间调整提示词Prompt却收效甚微本质原因是我们用开发“静态函数”的思维去构建“动态智能体”。循环工程的核心是解决智能体的“持续认知与行动”问题。它强调智能体不应是一次性的输入输出而应是一个拥有内部状态、能够根据环境反馈进行多轮次思考、决策和执行的循环系统。这类似于人类解决问题的方式观察、思考、行动、再观察。Harness工程则更进一步它关注如何为智能体套上“缰绳”Harness即一套控制、监控、评估和保障其安全合规运行的工程体系。它确保智能体在既定轨道上运行防止其产生有害输出、陷入死循环或执行危险操作。本文将解决的问题包括概念混淆厘清Agent、循环工程、Harness工程等术语的真实内涵与关联。架构缺失提供一套可落地的、用于构建复杂智能体的架构蓝图超越简单的LangChain链条。实践空白通过完整代码示例展示如何利用LangGraph等工具实现具有状态管理和工具调用能力的智能体。生产化瓶颈探讨如何为智能体添加监控、评估、安全护栏等生产级特性。如果你是一名希望将AI智能体从实验推向生产的开发者、架构师或技术负责人本文将为你提供关键的架构视角和实战路径。2. 基础概念与核心原理在深入实战前必须统一对几个核心概念的理解避免后续讨论产生歧义。2.1 AI智能体Agent的再定义一个真正的AI智能体不仅仅是“大模型提示词”。它是一个具备感知、规划、行动和从反馈中学习能力的自治系统。其核心组件通常包括大脑Brain通常是大语言模型LLM负责推理和决策。记忆Memory短期记忆对话历史、长期记忆向量数据库等用于维持状态和上下文。工具Tools智能体可以调用的外部函数或API如计算器、搜索引擎、数据库操作、代码执行器等用于扩展其能力边界。规划器Planner将复杂目标分解为可执行步骤的逻辑模块。2.2 循环工程从链到图的演进早期框架如LangChain提出了“链Chain”的概念但它本质上是线性的、预定义的流程。循环工程的思想是将智能体的执行过程建模为一个有状态的计算图。节点Nodes代表智能体可以执行的动作如“调用LLM”、“执行工具”、“更新记忆”。边Edges根据节点的输出结果决定下一步执行哪个节点。这通常由LLM或条件逻辑conditional edges来控制。状态State在整个图执行过程中流转和更新的共享数据上下文。这是实现多轮对话和复杂任务的关键。这种“图”的模型天然支持循环、分支、并行和条件跳转完美契合了智能体“思考-行动-观察”的循环本质。LangGraph正是基于这一理念构建的框架。2.3 Harness工程为智能体装上安全与控制的“缰绳”即使智能体具备了强大的循环执行能力若放任自流在生产环境中仍是危险的。Harness工程关注系统的外围保障层主要包括输入/输出过滤与净化检查用户输入是否包含恶意指令或敏感信息对模型输出进行后处理过滤不当内容。执行监控与超时控制跟踪每个工具调用的耗时、资源消耗并设置超时机制防止智能体“卡死”。权限与安全沙箱严格定义智能体可以调用哪些工具、访问哪些数据。对于代码执行等危险操作必须在隔离的沙箱环境中进行。评估与验证在关键决策点或最终输出前引入另一个LLM或规则系统对结果进行验证确保其正确性和安全性。可观测性记录完整的执行轨迹Thought Trace包括每一步的思考、工具调用及结果便于调试和审计。可以将Harness视为智能体运行时的“容器”或“管理平台”它不改变智能体的核心逻辑但确保了其行为在可控、可见、安全的范围内。2.4 概念关系图用户请求 ↓ [Harness层输入检查、权限验证] ↓ [智能体系统循环工程核心] ├── 状态管理 (State) ├── 规划与推理 (LLM) ├── 工具执行 (Tools) └── 记忆存储 (Memory) ↓ [Harness层输出过滤、结果验证、轨迹记录] ↓ 最终响应3. 环境准备与前置条件我们将使用Python和LangGraph框架来构建一个实战智能体。这个智能体能够理解复杂任务自主选择工具如搜索、计算并通过循环交互完成任务。基础环境要求操作系统macOS / Linux / Windows (WSL2推荐)Python版本3.10 或 3.11确保稳定性包管理工具pip 或 conda核心依赖安装创建一个新的虚拟环境并安装必要包。# 创建并激活虚拟环境以conda为例 conda create -n ai-agent python3.11 conda activate ai-agent # 安装核心框架和库 pip install langgraph langchain langchain-openai langchain-community # 安装用于向量记忆的库可选用于长期记忆 pip install chromadb # 安装用于网络搜索的工具库示例工具 pip install duckduckgo-searchAPI密钥配置本示例使用OpenAI的GPT模型作为智能体的“大脑”。你需要准备一个OpenAI API密钥。# 方式一设置环境变量推荐 export OPENAI_API_KEY你的-api-key-here # 方式二在代码中直接配置不推荐用于生产 # 将在后续代码中展示可选工具准备搜索工具我们将使用DuckDuckGoSearchRun作为示例它无需额外API密钥。计算工具使用langchain内置的Calculator。自定义工具你可以根据需要定义任何Python函数作为工具。4. 核心流程拆解构建一个循环智能体我们将构建一个名为“ResearchAssistant”的智能体它能根据用户问题决定是否需要搜索网络获取最新信息并结合计算等能力给出综合答案。4.1 第一步定义智能体的状态状态是智能体执行过程中的“共享内存”。我们使用TypedDict来明确定义。# 文件agent_state.py from typing import TypedDict, List, Annotated import operator class AgentState(TypedDict): 智能体运行时的状态定义 # 用户输入的问题 input: str # 智能体思考的中间过程链式思考 thoughts: Annotated[List[str], operator.add] # 已调用的工具及其结果列表 tool_calls: Annotated[List[dict], operator.add] # 最终要输出的答案 answer: strAnnotated和operator.add是LangGraph的语法糖用于声明该字段在多个节点间执行时应采用“追加”的合并策略而不是覆盖。4.2 第二步创建智能体可用的工具工具是智能体与外界交互的手脚。# 文件agent_tools.py from langchain_community.tools import DuckDuckGoSearchRun from langchain.tools import Calculator # 初始化工具 search_tool DuckDuckGoSearchRun() calculator_tool Calculator() # 将工具包装成LangChain可识别的列表 tools [search_tool, calculator_tool] # 你也可以创建自定义工具 from langchain.tools import tool import datetime tool def get_current_time(format: str %Y-%m-%d %H:%M:%S): 获取当前的日期和时间。 return datetime.datetime.now().strftime(format) # 将自定义工具加入列表 tools.append(get_current_time)4.3 第三步构建智能体的“大脑”LLM与规划器我们将创建一个支持工具调用的LLM并为其绑定工具描述。# 文件agent_brain.py from langchain_openai import ChatOpenAI from langchain.agents import create_openai_tools_agent from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder # 1. 初始化LLM使用gpt-4o-mini兼顾性能与成本 llm ChatOpenAI(modelgpt-4o-mini, temperature0) # 2. 定义提示词模板指导智能体如何思考和工作 prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的研究助手。请严格遵循以下步骤工作 1. 分析用户问题思考是否需要使用工具如搜索、计算来获取信息。 2. 如果需要一次只调用一个最合适的工具。 3. 根据工具返回的结果进行下一步思考。 4. 当你拥有足够信息可以完整、准确地回答用户问题时无需再调用工具直接给出最终答案。 请保持你的思考过程thoughts简洁明了。), MessagesPlaceholder(variable_namechat_history), # 预留对话历史的位置 (user, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 用于存放工具调用和结果的历史 ]) # 3. 创建Agent执行器负责调用LLM和工具 agent_executor create_openai_tools_agent(llm, tools, prompt)4.4 第四步使用LangGraph定义执行图这是循环工程的核心。我们将定义两个节点和一个条件边。# 文件agent_graph.py from langgraph.graph import StateGraph, END from .agent_state import AgentState from .agent_brain import agent_executor from langchain_core.messages import ToolMessage # 初始化图 graph_builder StateGraph(AgentState) # 定义节点1调用智能体思考并决定行动 def call_agent(state: AgentState): 智能体思考节点分析状态决定下一步是回答问题还是调用工具。 # 准备输入给agent_executor的格式 agent_input { input: state[input], chat_history: [], # 简化示例暂不引入复杂记忆 agent_scratchpad: [] # 简化示例 } # 执行智能体得到响应 response agent_executor.invoke(agent_input) # 更新状态记录思考过程 new_thoughts [f思考{response[output]}] if response.get(output) else [] # 检查是否有工具调用 tool_calls [] if response.get(intermediate_steps): for action, observation in response[intermediate_steps]: tool_calls.append({ tool: action.tool, input: str(action.tool_input), output: observation }) return { thoughts: new_thoughts, tool_calls: tool_calls, answer: response[output] if not tool_calls else # 如果调用了工具答案暂空 } # 定义节点2执行工具 def execute_tools(state: AgentState): 工具执行节点执行智能体请求的工具调用并将结果返回给状态。 last_tool_call state[tool_calls][-1] # 获取最新的工具调用请求 tool_name last_tool_call[tool] tool_input last_tool_call[input] # 根据工具名称找到对应的工具对象并执行 tool_map {tool.name: tool for tool in tools} tool_to_use tool_map.get(tool_name) if tool_to_use: try: result tool_to_use.invoke(tool_input) except Exception as e: result f工具执行出错{e} else: result f未知工具{tool_name} # 将工具执行结果以特定格式追加到状态中以便下一轮思考使用 # 这里简化处理实际LangGraph中可能需要更精细的消息传递 # 我们更新thoughts来携带结果信息 result_thought f工具 {tool_name} 执行结果{result} return {thoughts: [result_thought]} # 将节点添加到图中 graph_builder.add_node(agent, call_agent) graph_builder.add_node(execute_tools, execute_tools) # 设置入口点 graph_builder.set_entry_point(agent) # 定义条件边根据智能体输出决定下一步 def should_continue(state: AgentState): 路由逻辑如果上一轮调用了工具则去执行工具否则结束。 # 如果tool_calls列表不为空且最后一个工具调用还没有对应的output在我们的简化逻辑里有新的tool_calls就需要执行 # 更健壮的实现应检查是否有待执行的工具调用 if state.get(tool_calls) and len(state[tool_calls]) 0: # 这里可以添加更复杂的判断例如检查最后一个工具调用是否已执行 # 为简化我们假设只要有tool_calls且answer为空就需要执行工具 if not state.get(answer): return execute_tools # 否则结束流程 return END # 从“agent”节点出发根据条件路由 graph_builder.add_conditional_edges( agent, should_continue, { execute_tools: execute_tools, END: END } ) # 从“execute_tools”节点执行完后必须回到“agent”节点进行下一轮思考 graph_builder.add_edge(execute_tools, agent) # 编译图得到可执行的计算图 agent_graph graph_builder.compile()5. 完整示例与代码实现将以上模块整合并提供一个完整的运行示例。# 文件main.py import asyncio from agent_graph import agent_graph from agent_state import AgentState async def main(): 主运行函数 # 示例问题1需要搜索和综合信息 question1 截至2024年OpenAI最新的多模态模型是什么它有什么特点 # 示例问题2需要计算 question2 计算圆周率π乘以半径15的平方是多少 # 示例问题3简单问答 question3 你好请介绍一下你自己。 questions [question1, question2, question3] for idx, question in enumerate(questions, 1): print(f\n{*50}) print(f问题 {idx}: {question}) print(f{*50}) # 初始化状态 initial_state: AgentState { input: question, thoughts: [], tool_calls: [], answer: } # 执行智能体图 try: # 使用流式输出可以观察执行步骤这里为简化使用invoke final_state await agent_graph.ainvoke(initial_state) # 打印执行轨迹 print(\n[执行轨迹]) for i, thought in enumerate(final_state.get(thoughts, [])): print(f 步骤{i1}: {thought}) for i, tool_call in enumerate(final_state.get(tool_calls, [])): print(f 工具调用{i1}: {tool_call[tool]}(输入: {tool_call[input]})) print(f 结果: {tool_call.get(output, N/A)}) # 打印最终答案 print(f\n[最终答案]) print(f {final_state.get(answer, 未生成答案)}) except Exception as e: print(f执行过程中出现错误{e}) if __name__ __main__: asyncio.run(main())项目结构建议ai_agent_project/ ├── agent_state.py # 状态定义 ├── agent_tools.py # 工具定义 ├── agent_brain.py # LLM与提示词配置 ├── agent_graph.py # LangGraph图定义 ├── main.py # 主运行入口 └── requirements.txt # 依赖列表requirements.txt内容langgraph0.0.52 langchain0.1.0 langchain-openai0.0.8 langchain-community0.0.20 openai1.12.0 duckduckgo-search3.9.7 chromadb0.4.226. 运行结果与效果验证运行python main.py或python -m main你将看到类似以下的输出具体内容因模型和网络搜索结果而异 问题 1: 截至2024年OpenAI最新的多模态模型是什么它有什么特点 [执行轨迹] 步骤1: 思考用户想了解OpenAI截至2024年的最新多模态模型及其特点。我需要获取最新信息因此需要使用搜索工具。 工具调用1: duckduckgo_search_run(输入: OpenAI latest multimodal model 2024 features) 结果: [搜索返回的网页摘要例如提到GPT-4o等] 步骤2: 思考根据搜索结果OpenAI在2024年5月发布了GPT-4o这是一个原生的多模态模型可以实时处理文本、图像、音频。特点包括... 步骤3: 思考信息已足够无需再调用工具。 [最终答案] OpenAI在2024年发布的最新多模态模型是GPT-4o。它的主要特点是... 问题 2: 计算圆周率π乘以半径15的平方是多少 [执行轨迹] 步骤1: 思考这是一个数学计算问题。需要计算 π * r²其中r15。我应该使用计算器工具。 工具调用1: Calculator(输入: 3.141592653589793 * 15 * 15) 结果: 706.8583470577034 步骤2: 思考计算结果是706.8583470577034。可以直接给出答案。 [最终答案] 圆周率π乘以半径15的平方的结果是约706.86。 问题 3: 你好请介绍一下你自己。 [执行轨迹] 步骤1: 思考这是一个简单的问候和自我介绍请求不需要调用外部工具。我可以直接回答。 [最终答案] 你好我是一个AI研究助手由LangGraph等框架构建而成能够通过分析你的问题自主决定是否需要搜索网络信息或进行计算来帮助你获取准确答案。我的目标是高效、准确地协助你完成研究或解答疑问。如何验证成功流程正确性观察“执行轨迹”智能体应能正确判断何时调用工具问题1、2何时直接回答问题3。工具调用准确性对于计算问题工具调用输入应为正确的数学表达式并返回数值结果。答案完整性最终答案应基于工具返回的结果进行整合回答用户原始问题。状态流转thoughts和tool_calls列表应随着执行步骤逐步增长体现了状态的循环更新。7. 常见问题与排查思路在构建和运行此类智能体时你可能会遇到以下问题问题现象可能原因排查方式解决方案智能体不调用工具直接回答1. 提示词Prompt未明确要求使用工具。2. LLM温度temperature过高导致输出随机。3. 工具描述不清晰LLM无法理解其用途。1. 检查系统提示词确保包含使用工具的指令。2. 将temperature设为0确保确定性。3. 打印agent_executor可用的工具列表和描述。1. 优化提示词加入分步思考和使用工具的强引导。2. 使用更强大的模型如gpt-4。3. 为工具编写清晰、具体的描述。图执行陷入死循环1. 条件边should_continue逻辑有误导致在agent和execute_tools间无限循环。2. 工具执行结果未正确更新状态智能体反复请求同一工具。1. 在状态中增加steps计数器并在should_continue中检查是否超过最大步数。2. 打印每一轮的状态检查tool_calls和answer字段的变化。1. 在should_continue函数中添加最大循环次数限制。2. 确保execute_tools节点正确地将结果格式化为LLM能理解的上下文如追加到thoughts或chat_history。工具执行出错或超时1. 工具API不可用或网络错误。2. 工具输入参数格式错误。3. 工具执行耗时过长。1. 查看工具调用的异常堆栈信息。2. 单独测试工具函数确保其正常工作。3. 在工具调用外包裹超时控制逻辑。1. 在execute_tools函数中添加try...except将错误信息作为结果返回给智能体。2. 使用异步async调用工具并设置asyncio.wait_timeout。3. 实现工具调用的重试机制。状态State更新不符合预期1.TypedDict中Annotated字段的合并策略operator.add使用错误。2. 节点返回的字典键与State定义不匹配。1. 仔细阅读LangGraph文档关于状态合并的部分。2. 在每个节点函数开头和结尾打印输入和输出的状态。1. 确保列表类型字段使用Annotated[List, operator.add]。2. 节点返回值必须是State字典的子集且键名完全一致。记忆Memory不生效1. 未将历史消息正确传入提示词模板的MessagesPlaceholder。2. 状态中未设计存储历史消息的字段。1. 检查agent_input中是否包含了chat_history。2. 确认State定义中包含了对话历史字段。1. 在State中增加chat_history: Annotated[List, operator.add]字段。2. 在call_agent节点中将历史消息从state取出并格式化后传入LLM。8. 最佳实践与工程建议Harness工程化将上述循环智能体投入生产必须引入Harness工程思想。以下是一些关键实践8.1 输入/输出安全过滤输入净化在用户输入进入智能体前进行敏感词过滤、提示词注入攻击检测、长度限制。# 简化的输入检查函数 def sanitize_input(user_input: str, max_length1000): if len(user_input) max_length: raise ValueError(输入过长) # 简单的敏感词过滤生产环境应用更复杂的规则或模型 blacklist [恶意指令, 敏感词] for word in blacklist: if word in user_input: raise ValueError(输入包含不当内容) return user_input.strip()输出后处理对智能体的最终输出进行二次检查确保不泄露内部提示词、不包含歧视性或有害内容。可以使用一个轻量级的LLM或规则引擎进行校验。8.2 执行监控与可观测性全链路追踪利用LangGraph的回调Callbacks或自定义日志记录每个节点的输入输出、耗时、Token使用量。from langchain.callbacks import FileCallbackHandler import logging logging.basicConfig(levellogging.INFO, filenameagent_trace.log) handler FileCallbackHandler(agent_trace.log) # 在调用graph时传入callbacks[handler]设置超时与中断为整个图的执行或单个工具调用设置超时。import asyncio async def run_with_timeout(graph, state, timeout30): try: result await asyncio.wait_for(graph.ainvoke(state), timeouttimeout) return result except asyncio.TimeoutError: # 执行中断逻辑如保存当前状态返回超时提示 return {error: 请求超时}8.3 权限与沙箱隔离工具权限控制不是所有工具都对所有用户或所有问题开放。可以设计一个权限层根据用户身份或问题类型动态加载可用的工具列表。危险操作沙箱化对于代码执行、文件写入、系统命令等高风险工具必须在完全隔离的Docker容器或安全沙箱中运行并严格限制资源CPU、内存、网络。8.4 评估与验证流程关键结果验证对于涉及事实、数据或重要操作的结果引入“验证者”角色。例如在智能体给出一个数据结论后可以自动触发一个搜索工具进行交叉验证。A/B测试与评估在生产环境部署前构建一个评估数据集对比新旧智能体版本在回答准确性、工具使用合理性、耗时等指标上的差异。8.5 配置化与版本管理将提示词、工具列表、图结构外置为配置如YAML文件便于不同环境开发、测试、生产的切换和版本回滚。对智能体进行版本化当更新提示词、工具或模型时能够清晰地追踪变更和影响。9. 总结与后续学习方向通过本文的拆解与实战我们完成了从“循环工程”理论到“Harness工程”实践的跨越。我们构建的不仅仅是一个能调用工具的AI而是一个具备状态感知、自主规划、循环执行能力的智能体系统框架。LangGraph提供的图计算模型是实现这一循环的绝佳抽象。本文的核心价值在于澄清了循环工程是智能体的“内功”关注其内部的思考-行动循环与状态管理。Harness工程是智能体的“外功”关注其运行时的安全、可控与可观测。两者结合才能打造出真正可靠、可用的生产级AI智能体。你的后续行动建议扩展工具集将你的业务API如数据库查询、CRM操作、内部知识库检索封装成工具让智能体真正融入你的工作流。引入长期记忆集成向量数据库如Chroma让智能体能够记住跨对话的信息实现更个性化的服务。探索更复杂的图结构尝试StateGraph中的分支、并行、子图等高级特性处理需要多智能体协作或复杂审批流的任务。搭建监控面板使用Grafana、LangSmith等工具将智能体的运行指标延迟、成本、错误率可视化。深入研究安全合规特别是涉及用户数据、金融、医疗等敏感领域时必须设计严格的输入输出审查和审计日志。AI智能体的工程化之路刚刚开始。掌握循环与Harness这两大核心思想意味着你掌握了将前沿AI能力转化为稳定生产力的关键。从今天这个可运行的示例出发逐步叠加监控、安全、评估层你就能构建出经得起业务考验的智能体系统。