ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从提示词到生产系统:Agent框架工程化实战指南

从提示词到生产系统:Agent框架工程化实战指南 1. 项目概述为什么我们需要一个“Agent 框架工程”最近和不少做AI应用的朋友聊天发现一个挺有意思的现象大家都能用OpenAI的API或者开源的Llama模型快速搭出一个能对话的Demo。但一旦想把Demo变成一个能稳定运行、能处理复杂任务、能对接真实业务系统的“智能体”就立刻卡住了。问题五花八门对话状态怎么管理工具调用失败了怎么回退多个Agent之间怎么协作系统的并发和稳定性怎么保证这感觉就像你有了一个超级聪明的大脑大模型但缺了一副能跑能跳、能拿工具、能抗摔打的“身体”和“神经系统”。这就是“Agent框架工程”要解决的问题。它不是一个具体的Agent比如帮你写周报或者订机票的机器人而是一套基础设施和工程规范。你可以把它想象成开发Android应用时的Android SDK和一系列设计模式如MVVM。SDK提供了访问摄像头、网络、存储等基础能力而设计模式告诉你如何优雅地组织代码让应用易于维护和扩展。Agent框架工程干的也是类似的事它为大模型这个“大脑”提供感知环境、使用工具、记忆历史、规划决策的“标准接口”和“最佳实践”让开发者能聚焦在业务逻辑本身而不是反复造轮子。从网络热词里频繁出现的“Harness工程”、“Agent开发”、“大模型部署”就能看出社区已经意识到单纯调API的“提示词工程”时代正在过去下一个阶段是“AI工程化”的深水区。这个项目就是试图梳理和构建这片深水区里的核心基础设施。2. Agent框架的核心架构与设计哲学一个健壮的Agent框架远不止是“用LangChain连几个工具”那么简单。经过多个项目的实践和踩坑我认为一个面向生产的Agent框架需要自上而下地思考几个层次。2.1 分层架构从大脑到肢体一个完整的Agent系统可以抽象为四层认知与决策层大脑这是大模型本身负责理解用户意图、分解任务、生成计划Plan和具体指令。框架在这里需要提供的是提示词模板管理、思维链CoT或思维树ToT等推理框架的集成以及对多种模型GPT、Claude、GLM、本地模型的统一抽象。关键是要把模型的“思考过程”结构化而不仅仅是获取最终输出。记忆与状态层海马体与工作记忆Agent必须有记忆。这包括短期记忆/对话历史当前会话的上下文。不能无脑地把所有历史对话都塞进上下文窗口需要智能的摘要、压缩或选择性保留。长期记忆/向量知识库Agent的“个人知识库”用于存储和检索超出上下文窗口的信息。这里涉及向量数据库选型Chroma, Pinecone, Weaviate、Embedding模型选择以及检索策略相似度搜索、混合搜索、重排序。状态管理Agent执行一个多步骤任务时的当前状态。比如在“订机票-选座位-支付”流程中到了哪一步收集了哪些信息目的地、时间、乘客这需要一套状态机或工作流引擎来管理。工具与执行层四肢与工具这是Agent与外部世界交互的桥梁。框架需要提供工具抽象与注册机制如何将一段Python函数、一个API接口、甚至一个命令行工具安全、规范地暴露给Agent调用。这包括工具的描述让模型理解工具能干什么、参数的模式化定义JSON Schema。工具执行引擎负责安全地执行工具代码处理超时、异常并格式化返回结果给模型。这里的安全隔离如沙箱至关重要。工具编排当需要按顺序或并行调用多个工具时如何管理它们之间的依赖和数据传递。编排与流程层神经系统这是框架最核心的价值之一负责协调上述所有层。控制流Control Flow决定Agent下一步该“想”什么调用模型还是“做”什么调用工具。是经典的 ReAct (Reasoning Acting) 循环还是更复杂的规划-执行-检查-调整Plan-Execute-Check-Adjust循环多Agent协作当任务复杂时可能需要多个各司其职的Agent如一个“规划者”一个“执行者”一个“审查者”协同工作。框架需要定义Agent间的通信协议共享黑板、消息队列、协作模式主从、对等、流水线。持久化与可观测性每一次Agent运行的完整轨迹Thought, Action, Observation都需要被记录、存储用于调试、分析和再训练。这直接关系到系统的可维护性。2.2 设计原则什么才是“好”的框架基于这些分层我们在设计或选型框架时应该遵循几个原则松耦合与高内聚认知层、记忆层、工具层应该模块化可以独立替换。比如从GPT-4换到Claude 3或者从Chroma换到Milvus不应该引起业务代码的剧烈变动。声明式优于命令式尽可能用配置YAML/JSON来描述Agent的能力、流程和工具而不是硬编码在Python里。这提升了可读性和可维护性。可观测性第一Agent的内部决策过程是个黑盒不行。框架必须原生提供强大的日志、追踪Trace和监控能力让你能清晰地看到“Agent为什么这么想/这么做”。为失败而设计工具调用会超时、模型会返回乱码、网络会抖动。框架必须有完善的错误处理、重试、回退Fallback和超时机制。一个遇到错误就崩溃的Agent是不可用的。3. 主流框架深度对比与选型指南现在市面上Agent框架很多各有侧重。单纯看GitHub星星数不够得结合你的实际需求来选。3.1 框架生态全景图我们可以把主流框架分为几类框架类别代表项目核心特点适用场景工程化考量应用构建型LangChain / LangGraph生态最繁荣工具链最全文档加载、向量库、链。LangGraph 强化了有状态、多Agent的工作流编排。快速原型验证构建复杂的、包含多步骤检索和工具调用的应用。社区资源多学习成本相对低。早期版本API变动频繁生产部署需要自己封装和优化。LangGraph 的状态管理概念是核心优势。轻量级与专注型LlamaIndex最初专注RAG检索增强生成现在也扩展了Agent能力。在数据连接和检索方面非常强。如果你的核心场景是让Agent基于私有知识库问答和推理LlamaIndex是绝佳起点。与LangChain部分功能重叠可结合使用。其Agent模块更偏向于基于检索的智能体。生产就绪型AutoGen (微软)主打多Agent对话协作提供了定义Agent角色、对话模式的编程范式。学术和复杂协作场景见长。研究性质的多Agent系统、需要模拟社会性交互如辩论、评审的场景。配置稍显复杂性能开销需要关注更适合作为后台“大脑”而非直接面向用户。新兴势力CrewAI在LangChain基础上更强调Role角色、Goal目标、Task任务的抽象面向企业级工作流。需要清晰定义组织架构如一个产品经理Agent、一个工程师Agent、一个测试员Agent协作的自动化流程。概念清晰易于理解但相对年轻生态和稳定性在发展中。底层框架Semantic Kernel (微软)更像一个SDK提供了规划器Planner、记忆、技能的底层抽象与.NET生态结合深。已有大量C#/.NET资产的企业希望深度集成AI能力到现有产品中。学习曲线较陡需要更深入的编程投入但灵活性和控制力也最强。注意没有“银弹”。LangChain 可能因为其“大而全”在简单场景下显得笨重但在复杂场景下其丰富的集成能力又是无可替代的。从“热词”中看到很多人搜索“Harness工程”Harness 的理念正是提供一套包裹在Agent核心逻辑之外的可靠性基础设施如评估、监控、部署这与框架的选型是互补的。3.2 选型决策树我该用哪个你可以通过回答下面几个问题来缩小选择范围你的团队主要技术栈是什么Python 全栈LangChain/LlamaIndex/CrewAI 是首选生态好。C# / .NET认真考虑 Semantic Kernel。Java社区有类似框架但不如Python生态成熟可能需要更多自研或基于Python服务做集成。你的核心场景是什么复杂对话与工具调用LangChain LangGraph。私有知识库问答RAGLlamaIndex 起步再结合Agent。模拟多角色协作如虚拟公司AutoGen 或 CrewAI。嵌入现有业务系统作为增强模块Semantic Kernel 或 LangChain作为库调用。你对性能和可控性的要求有多高要求极高愿意投入研发可以考虑基于更底层的库如 OpenAI SDK, litellm自研框架或深度定制 Semantic Kernel。追求开发效率接受一定性能损耗直接使用成熟的 LangChain 或 CrewAI。个人心得对于大多数从0到1的团队我建议从LangChain开始。不是因为它最好而是因为它的文档、教程、社区问题和解决方案最丰富。你遇到的90%的坑大概率都有人踩过。在快速验证想法后如果发现其某些模块成为性能瓶颈或不够灵活再对其进行替换或重构是更稳妥的路径。切忌在项目初期陷入“框架选型焦虑”。4. 工程化实践从Demo到生产系统假设我们选定 LangGraph 来构建一个“智能旅行规划Agent”。下面看看如何将它工程化。4.1 项目结构与配置管理一个生产级的Agent项目代码组织不能是Jupyter Notebook或单个脚本。travel_agent_project/ ├── config/ # 配置中心 │ ├── agents.yaml # Agent角色定义系统提示词、模型配置 │ ├── tools.yaml # 工具注册列表API密钥、参数默认值 │ └── workflows.yaml # 工作流图定义LangGraph StateGraph ├── src/ │ ├── agents/ # Agent实现类 │ │ ├── planner.py # 规划Agent │ │ ├── researcher.py # 信息检索Agent │ │ └── booker.py # 预订Agent │ ├── tools/ # 工具集 │ │ ├── web_search.py │ │ ├── flight_api.py │ │ └── weather_api.py │ ├── memory/ # 记忆模块 │ │ ├── short_term.py │ │ └── long_term.py │ ├── graph/ # 工作流图定义 │ │ └── travel_plan_graph.py │ └── schemas.py # 共享的Pydantic数据模型 ├── tests/ # 测试 ├── scripts/ # 部署和管理脚本 ├── .env.example # 环境变量模板 ├── requirements.txt ├── Dockerfile └── README.md关键点使用YAML等配置文件管理提示词、模型参数和工具元数据实现配置与代码分离。这样调整Agent的“性格”或更换API端点无需重新部署代码。4.2 状态State设计工作流的基石在LangGraph中State是所有节点共享的数据结构。设计好State是成功的关键。# schemas.py from typing import TypedDict, List, Annotated from langgraph.graph.message import add_messages import operator class TravelState(TypedDict): # 用户原始输入 user_input: str # 消息历史LangGraph内置的线程安全操作 messages: Annotated[List, add_messages] # 解析后的用户意图结构化数据 parsed_intent: dict # 规划Agent生成的旅行计划草稿 plan_draft: str # 研究Agent收集到的景点/酒店信息 research_results: List[dict] # 预订Agent执行后的确认信息 booking_confirmation: dict # 当前流程步骤 current_step: str # 错误信息如果有 error: str为什么这么设计TypedDict提供了类型提示利于开发和调试。Annotated与add_messages是LangGraph的魔法它确保了对消息列表的修改是线程安全的。将不同Agent的产出放在不同的字段避免了状态污染也使得每个节点的职责更清晰。4.3 构建健壮的工作流图在travel_plan_graph.py中我们构建一个包含条件判断和循环的图。from langgraph.graph import StateGraph, END from .agents import PlannerAgent, ResearcherAgent, BookerAgent, HumanInTheLoop from .tools import validate_budget # 初始化各个节点Agent或函数 planner PlannerAgent() researcher ResearcherAgent() booker BookerAgent() human_check HumanInTheLoop() validator validate_budget # 创建图 workflow StateGraph(TravelState) # 添加节点 workflow.add_node(“parse_and_plan”, planner.run) # 解析意图并制定计划 workflow.add_node(“research_details”, researcher.run) # 研究细节 workflow.add_node(“make_booking”, booker.run) # 执行预订 workflow.add_node(“human_review”, human_check.run) # 人工审核 workflow.add_node(“validate”, validator) # 预算校验 # 设置入口点 workflow.set_entry_point(“parse_and_plan”) # 添加边定义执行顺序 workflow.add_edge(“parse_and_plan”, “research_details”) workflow.add_edge(“research_details”, “validate”) # 条件边根据预算校验结果决定下一步 def route_after_validation(state: TravelState): if state.get(“error”): return “human_review” # 预算超支转人工 else: return “make_booking” # 预算合理继续预订 workflow.add_conditional_edges( “validate”, route_after_validation, {“human_review”: “human_review”, “make_booking”: “make_booking”} ) workflow.add_edge(“make_booking”, END) workflow.add_edge(“human_review”, END) # 编译图 app workflow.compile()实操要点节点要单一职责每个节点只做一件事并明确修改State中的哪个部分。善用条件边这是实现复杂业务逻辑如审核、重试的关键。预编译compile()后的app对象可以序列化保存提高运行时效率。4.4 工具层的安全与可靠性封装工具是风险高发地。绝对不能直接把未经处理的用户输入传给工具。# tools/flight_api.py import os import httpx from pydantic import BaseModel, Field from typing import Optional from datetime import date class FlightSearchInput(BaseModel): origin: str Field(description“出发地机场三字码如 PEK”) destination: str Field(description“目的地机场三字码如 JFK”) departure_date: date Field(description“出发日期格式 YYYY-MM-DD”) max_price: Optional[float] Field(defaultNone, description“最高可接受价格单位人民币”) tool(“search_flights”, args_schemaFlightSearchInput) def search_flights(origin: str, destination: str, departure_date: date, max_price: float None): “”“根据条件搜索航班。会对参数进行安全校验和格式化。”“” # 1. 参数校验与清洗 origin origin.upper().strip() if len(origin) ! 3: raise ValueError(f“Invalid airport code: {origin}”) # ... 其他校验 # 2. 构造安全的请求防止SQL注入/命令注入 api_key os.getenv(“FLIGHT_API_KEY”) url f“{os.getenv(‘FLIGHT_API_BASE’)}/search” params { “from”: origin, “to”: destination, “date”: departure_date.isoformat() } if max_price: params[“maxPrice”] max_price # 3. 带超时和重试的请求 with httpx.Client(timeout30.0) as client: try: resp client.get(url, paramsparams, headers{“Authorization”: f“Bearer {api_key}”}) resp.raise_for_status() data resp.json() except httpx.RequestError as e: # 记录详细日志但返回给Agent的信息要友好 logger.error(f“Flight API request failed: {e}”) return “航班查询服务暂时不可用请稍后再试或尝试更换日期。” except httpx.HTTPStatusError as e: logger.error(f“Flight API returned error: {e.response.status_code}”) return “无法获取航班信息可能是参数有误或服务异常。” # 4. 格式化结果便于模型理解 flights data.get(“flights”, []) if not flights: return “未找到符合条件的航班。” # 简化并结构化返回信息 result_str “\n”.join([f“{f[‘airline’]} {f[‘flight_no’]}: {f[‘departure’]} - {f[‘arrival’]}, 价格 ¥{f[‘price’]}” for f in flights[:3]]) # 只返回前3条 return f“找到以下航班选项\n{result_str}”避坑指南输入验证必须使用Pydantic Schema严格定义和校验输入这是防止“提示词注入”导致工具滥用的第一道防线。防御性编程工具内部要对所有外部调用API、数据库做异常处理并返回对Agent友好的错误信息而不是让整个流程因一个API挂掉而崩溃。超时设置任何网络请求都必须设置超时避免一个慢请求拖死整个Agent线程。结果格式化返回给模型的结果应该简洁、结构化避免把原始的、冗长的JSON直接扔过去浪费Token还可能干扰模型判断。5. 部署、监控与持续迭代5.1 部署模式选择API服务模式推荐将编译好的LangGraphapp包装成FastAPI或Flask服务。提供/invoke和/stream端点。这是最灵活的方式便于水平扩展和集成。# app/main.py from fastapi import FastAPI from .graph import app as agent_graph from .schemas import TravelStateInput api FastAPI() api.post(“/plan”) async def create_plan(input: TravelStateInput): # 初始化状态 initial_state {“user_input”: input.user_input, “messages”: []} # 异步执行图支持流式输出 async for event in agent_graph.astream(initial_state, stream_mode“values”): yield event # 可以返回SSE流 # 或者同步执行 # final_state agent_graph.invoke(initial_state) # return final_state异步任务队列对于耗时长的任务如研究阶段需要搜索大量信息可以将Agent调用封装为Celery或Dramatiq任务避免阻塞HTTP请求。容器化使用Docker打包整个应用包括Python环境、依赖和模型文件如果是本地小模型。用Kubernetes或Docker Compose管理多实例部署。5.2 可观测性给Agent装上“眼睛”没有监控的Agent上线等于盲人骑瞎马。必须记录完整的执行轨迹。# 在LangGraph中可以通过配置检查器Checkpointer和自定义回调来实现 from langgraph.checkpoint.sqlite import SqliteSaver from langgraph.checkpoint.base import BaseCheckpointSaver import json # 1. 使用检查器持久化每个步骤的状态 memory SqliteSaver.from_conn_string(“:memory:”) # 生产环境用持久化数据库 app workflow.compile(checkpointermemory) # 2. 自定义回调记录日志和指标 class ObservabilityCallback: def on_agent_action(self, action): # 记录工具调用请求 logger.info(f“Agent attempting action: {action}”) metrics.counter(“agent.actions.attempted”).inc() def on_agent_finish(self, finish): # 记录最终输出 logger.info(f“Agent finished: {finish}”) def on_tool_start(self, tool_input): # 记录工具输入 logger.debug(f“Tool input: {tool_input}”) def on_tool_error(self, error): # 记录工具错误 logger.error(f“Tool error: {error}”) metrics.counter(“tool.errors”).inc() # 在调用时传入回调 config {“configurable”: {“thread_id”: “user_123”}, “callbacks”: [ObservabilityCallback()]} result app.invoke({“user_input”: “…”}, configconfig)监控指标业务指标任务完成率、平均完成步骤数、人工干预率。性能指标每个节点的耗时、Token消耗量、工具调用延迟。质量指标通过抽样或自动化测试评估最终输出的准确性和有用性。成本指标关联每次调用的模型费用和API调用费用。5.3 评估与持续迭代构建飞轮Agent系统不是一蹴而就的需要持续评估和优化。构建评估数据集收集真实用户query和期望的Agent行为轨迹Golden Path。自动化测试流水线单元测试测试单个工具函数、单个Agent节点的输出。集成测试测试完整的工作流图给定固定输入断言最终的State或输出。基于LLM的评估用另一个LLM如GPT-4作为裁判评估Agent输出的相关性、正确性和安全性。这可以集成到CI/CD中。分析轨迹日志定期查看失败或低效的案例。是工具不好用还是提示词有歧义或者是流程设计有缺陷根据分析结果迭代提示词、工具或图结构。A/B测试对于关键节点如规划Agent的提示词可以部署不同版本通过流量分割对比效果。踩坑实录我们曾有一个“邮件处理Agent”初期准确率很高。但随着业务变化新类型的邮件出现准确率逐渐下降。后来我们建立了一个闭环将所有低置信度的处理结果自动转人工人工处理后的正确结果连同原始邮件自动加入评估数据集。每周用这个增强的数据集微调一下提示词甚至重新训练一下分类模型如果用了的话Agent的性能就又能跟上业务变化了。这个“生产-收集-评估-优化”的飞轮是Agent系统保持活力的关键。6. 避坑指南与进阶思考6.1 新手常犯的五个错误过度依赖大模型试图用一个超长的提示词让模型做完所有事。结果提示词难以维护效果不稳定。正确做法把复杂任务拆解成由多个简单、专注的Agent或节点组成的工作流。忽视状态管理在多个函数间用全局变量传递状态导致并发时数据错乱。正确做法严格使用框架提供的状态管理如LangGraph的State它是为并发设计的。工具不做防护允许模型直接拼接字符串调用系统命令或SQL。这是极大的安全漏洞。正确做法所有工具必须做严格的输入验证和输出过滤关键操作需有二次确认或权限控制。没有超时和回退网络调用或模型响应没有超时设置一个环节卡死整个流程。正确做法为所有外部依赖设置合理的超时并设计降级方案如工具调用失败后转向备用API或提示用户手动输入。忽略成本和延迟无节制地使用最高级的模型和最详细的上下文导致单次调用成本高、速度慢。正确做法进行分层设计简单任务用小模型复杂任务再用大模型。对上下文进行压缩和总结。6.2 进阶方向当你的Agent系统需要更强大动态工作流当前的工作流图是预定义的。更高级的模式是根据运行时情况动态生成或修改图结构。这需要模型具备更强的规划和推理能力。长期记忆与个性化如何让Agent记住与特定用户的长期交互历史并提供个性化服务这需要更复杂的记忆索引和检索策略并妥善处理隐私问题。多模态能力集成让Agent不仅能处理文本还能看图像理解、听语音识别、说语音合成。这涉及到多模态模型的编排和同步。与现有系统深度集成Agent如何安全、高效地操作CRM、ERP等核心业务系统这需要设计更精细的权限模型和操作审计日志。构建Agent框架工程本质上是在为大模型这个“世界模型”建造通往物理世界和数字世界的“桥梁与工具”。这条路没有终点充满了挑战但也正是其魅力所在。每一次对框架的优化每一次对流程的打磨都让我们离真正智能、可靠的AI助手更近一步。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进