
1. 项目概述1.1 这个智能体项目到底要做什么我团队最近把一个 AI 智能体应用从零开发到正式上线跑完了完整流程。趁热把整条链路拆开记录一下包括架构怎么搭、代码怎么组织、上线要处理哪些坑尤其是“AI Agent 怎么扛并发”这个话题网上讨论很多但都是零散片段我这里给出一份完整落地经验。先说清楚这个项目的定位我们要做的不是那种套壳聊天机器人而是一个能自主完成业务任务的智能体——接收用户意图后它会自己去调大模型、查知识库、调外部工具接口最后汇总输出结果。以电商场景为例用户问“帮我对比这三款耳机选一个性价比最高的”智能体需要自主规划步骤先调用搜索工具获取产品信息再调用评测数据源分析口碑最后用大模型综合推理给出推荐结论。整个过程用户只给一句话剩下的由智能体自己完成。项目最终跑通的核心能力有四点多工具调用、工作流编排、记忆管理、并发支撑。这篇文章不只是写代码更多是告诉你每个环节为什么这么做、上线前哪些地方必须做压力测试、遇到问题怎么排查。适合正在做 AI Agent 开发、想从 demo 走向生产环境的工程师也适合刚接触智能体开发、需要一份完整路线图的新手。1.2 从零到一的技术选型总览技术选型直接决定了后续开发效率。我们最终采用的核心栈如下层级选型选型理由大模型底座DeepSeek API主要 备用模型便宜、响应快推理能力强适合多轮工具调用编排框架LangChain LangGraph生态成熟图编排能清晰管理多步工具调用流程应用框架FastAPI原生异步支持高并发场景下性能远优于 Flask并发层Celery Redis处理耗时的异步任务避免请求线程被长时间占用存储PostgreSQL pgvector知识库向量检索一套数据库搞定结构化与非结构化数据前端React 轻量页面与后端纯 API 交互不做重逻辑选这套组合最核心的原因是异步能力。AI Agent 的请求有个特点一个用户请求可能内部要调好几次大模型 API单次就可能耗时 5-10 秒。如果用同步阻塞模型50 个并发请求就能把服务拖垮。FastAPI 的异步机制配合任务队列才能把单机支撑能力提上去。这一点后面并发章节会重点展开。2. AI Agent 核心架构设计思路2.1 智能体的基本运行原理在动手写代码前先要把智能体的运行机制搞清楚。市面上的 AI Agent 框架五花八门但本质都逃不出这个循环用户输入 → 意图理解 → 任务规划 → 工具调用 → 结果整合 → 输出回复如果用生活化类比AI Agent 像一个“有手有脚”的员工而传统聊天机器人只是一个“只有嘴”的客服。普通聊天机器人收到问题后直接让大模型回答但 Agent 收到问题后会自己判断“这个问题我需要查数据库才能回答”“这个问题我需要调用天气 API”然后真的去调用这些工具拿到数据后再组织语言回复。LangGraph 的到来基于图结构来管理这个循环。每个节点代表一个处理步骤比如“意图识别节点”“工具调用节点”“结果汇总节点”边代表流转条件。好处有三个流程可视化出问题能直接看到卡在哪个节点。支持条件分支比如“如果工具调用失败走重试分支”。天然具备状态管理能力每轮对话的上下文可以持久化。2.2 工作流编排为什么选 LangGraph 不选纯 LangChain很多初学者上来就用 LangChain 的Chain串任务但遇到真实业务场景就会发现它的局限Chain 适合固定流程不适合动态规划。比如“用户问天气你调天气工具”这个流程很固定用 Chain 没问题但“用户让智能体帮忙规划一周健身计划”这种任务大模型需要动态判断——是先查询用户体能数据还是直接生成计划这没办法提前写死。LangGraph 给了一个更合理的解法让大模型决定走哪条边。我在这里可以给出一个简化的图结构示意from langgraph.graph import StateGraph, END # 定义状态对象保存对话上下文和中间结果 class AgentState(TypedDict): messages: list pending_tools: list final_answer: str # 节点1理解用户意图 def understand_intent(state: AgentState): # 调用大模型识别意图和所需工具 return {pending_tools: [search_product, analyze_reviews]} # 节点2执行工具调用 def execute_tools(state: AgentState): for tool in state[pending_tools]: result tools_registry[tool].run(...) return {messages: state[messages] [result]} # 节点3生成最终回答 def generate_answer(state: AgentState): return {final_answer: llm_call(...)} # 构建图 builder StateGraph(AgentState) builder.add_node(understand, understand_intent) builder.add_node(execute, execute_tools) builder.add_node(generate, generate_answer) builder.add_edge(understand, execute) builder.add_edge(execute, generate) builder.add_edge(generate, END) graph builder.compile()这个示例代码已经能跑通最基本的“理解-执行-生成”循环生产环境里还需要加上“重试机制”“兜底回答”“人工介入审批”等判断边。架的图从 3 个节点开始后面会滚到 10-15 个节点所以从一开始就用图而非线性 Chain给后续扩展留好余地。2.3 工具调用机制Function Calling 的落地细节智能体要“下地干活”靠的是工具调用。大模型本身不会执行代码但是它能根据用户意图输出结构化的“工具调用请求”然后由你的后端代码真正去执行。这个机制在 OpenAI 叫 Function Calling在 DeepSeek 平台也有对应支持。我强烈建议所有 Agent 的工具都通过统一的注册表管理不要散落在业务代码里。下面是我一直在用的工具注册方式class ToolRegistry: def __init__(self): self.tools {} def register(self, name: str, description: str, parameters: dict, handler: Callable): self.tools[name] { name: name, description: description, parameters: parameters, handler: handler } def get_tool_schema(self): 把工具定义转换成 OpenAI/DeepSeek 兼容的 schema return [ { type: function, function: { name: t[name], description: t[description], parameters: t[parameters] } } for t in self.tools.values() ] def execute(self, name: str, arguments: dict): if name not in self.tools: raise ValueError(fTool {name} not registered) return self.tools[name][handler](**arguments) # 注册工具示例查数据库 def query_inventory(product_name: str): 查询商品库存 result db.query(SELECT stock FROM inventory WHERE product ?, product_name) return {in_stock: len(result) 0, stock: result[0] if result else 0} registry ToolRegistry() registry.register( namequery_inventory, description查询商品库存情况, parameters{ type: object, properties: { product_name: {type: string, description: 商品名称} }, required: [product_name] }, handlerquery_inventory )工具注册表设计有一个细节很重要工具描述一定要写清楚什么时候用、什么时候不用。大模型选择工具靠的是描述文本匹配度描述写得好工具调用准确率能提升 20-30%。我经历过一个真实例子某个工具描述写得太模糊模型经常在不需要的时候也去调用它导致响应时间翻倍。3. 开发环境与工程化搭建3.1 项目结构规划一个生产级 AI Agent 项目不能把代码全塞在几个文件里。我推荐按功能模块拆分为清晰的结构agent-project/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── config.py # 配置管理模型 key、数据库连接等 │ ├── models/ # 数据模型 │ ├── agents/ # 智能体编排逻辑 │ │ ├── graph.py # LangGraph 图的定义 │ │ └── nodes/ # 节点函数 │ ├── tools/ # 工具注册与实现 │ │ ├── registry.py │ │ ├── search.py │ │ ├── database.py │ │ └── api_tools.py │ ├── memory/ # 记忆管理 │ ├── services/ # 业务服务层 │ ├── llm/ # 大模型接口封装 │ └── utils/ ├── celery_app/ # 异步任务队列 ├── tests/ # 自动化测试 ├── scripts/ # 部署脚本 ├── docker-compose.yml └── requirements.txt按照这种结构团队成员可以并行开发不同模块工具开发者不用关心智能体编排逻辑编排开发者不用理解业务 API 细节。代码库变大以后这个优势会越来越明显。3.2 DeepSeek 大模型接口的接入实践模型接入这块我以 DeepSeek 为例说明实践方法。DeepSeek 平台提供的是 OpenAI 兼容接口所以客户端可以直接用 OpenAI SDK只需改 base_url 即可from openai import OpenAI client OpenAI( api_keyyour-api-key, base_urlhttps://api.deepseek.com ) def chat_with_tools(user_message: str, tool_schemas: list, history: list): 带工具调用的对话 response client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: 你是一个智能客服助手可以调用工具来获取信息。}, *history, {role: user, content: user_message} ], toolstool_schemas, tool_choiceauto # 让模型自动决定是否调用工具 ) return response.choices[0].message接入时有几个非常实用的经验第一模型选择要区分不同任务类型。简单文本生成用 deepseek-chat复杂推理和工具调用用 deepseek-reasoner。我实测下来在需要多步规划的任务中reasoner 的准确率明显更高但它出第一个 token 的时间也更长所以要根据场景取舍。第二上下文长度是成本控制的核心。每次都把完整历史记录发给模型成本会爆炸。我建议在中间层做“记忆压缩”对话超过一定轮数后让大模型把前面内容总结成一个摘要后续请求只带摘要加最近几轮原文。第三响应解析必须做重试保护。大模型的输出偶尔会不遵循 JSON 格式尤其是使用工具调用返回参数时。我封了一个解析函数如果第一次解析失败就提示大模型“你的输出不是合法 JSON请重新输出”最多重试两次还不成功就走兜底流程。3.3 向量数据库与知识库接入Agent 要回答专业性问题光靠模型内部知识不够必须接外部知识库。我用的是 PostgreSQL 加 pgvector 扩展省去搭独立向量数据库组件的运维负担。嵌入模型方面如果预算有限直接走 DeepSeek 平台的 embedding 接口如果对数据隐私要求高可以本地部署开源的嵌入模型。向量检索的核心代码如下import pgvector from sqlalchemy import create_engine, text class KnowledgeBase: def __init__(self, conn_str): self.engine create_engine(conn_str) def search(self, query: str, embedding_model, top_k: int 5, threshold: float 0.7): 根据问题检索最相关的知识库片段 query_embedding embedding_model.embed(query) sql text( SELECT content, source, 1 - (embedding :query_emb) as similarity FROM documents WHERE 1 - (embedding :query_emb) :threshold ORDER BY embedding :query_emb LIMIT :top_k ) with self.engine.connect() as conn: rows conn.execute(sql, { query_emb: query_embedding, threshold: threshold, top_k: top_k }).fetchall() return rows阈值设多少很关键。设太低会混入大量无关内容污染回答质量设太高会召回不到有用信息。我用 0.7 作为初始值然后根据测试集不断校准这个值在不同业务领域会差异很大需要实际调参。4. 核心功能实现与关键代码拆解4.1 意图识别与多工具决策流程刚才的代码里注册了单个工具但真实业务不会只挂一个工具。用户需求千变万化智能体需要自己组合多个工具完成任务。比如用户问“帮我找到价格在 500 以下、好评率超过 90% 的蓝牙耳机然后推荐一款”。这个任务至少涉及三步查商品库、查评价数据、综合推荐。大模型要自己判断工具调用顺序。实际执行时模型可能第一次输出“我需要先调用 search_products”得到结果后第二次再输出“我需要调用 analyze_reviews”依次推进。LangGraph 透出当前状态与大模型历史交互可以实现这个多轮工具调用闭环。这种设计要特别注意循环控制。如果模型陷入“反复调用同一个工具不结束”必须有最大调轮限制。我设置 max_iterations5超过就直接强制生成总结避免消耗失控和死循环。4.2 记忆系统短期上下文与长期用户画像Agent 没有记忆就跟金鱼一样用户每句话都要重复自己的信息。记忆设计分成两层短期记忆是当前会话上下文存在 Redis 里设置过期时间。每个会话会话通过 session_id 关联接口请求都带这个参数。长期记忆存储用户偏好和画像放在 PostgreSql 表格里。比如用户之前说过“我喜欢偏暖色调的灯光”这个信息会被提取出来写入用户画像字段。下次对话智能体就能主动考虑这个偏好。我实现了一个记忆提取函数def extract_long_term_memory(user_id: str, conversation: list): 从对话中提取值得长期记忆的信息 prompt f 浏览以下对话内容提取值得长期记住的用户偏好信息。 只提取明确表达的偏好、事实约束、身份信息不要提取模糊推测。 输出 JSON 数组格式[{{key: 偏好名称, value: 偏好内容}}] 对话内容: {conversation} response llm_call(prompt) memories parse_json(response) for mem in memories: save_user_memory(user_id, mem[key], mem[value])这个能力上线后对用户留存提升非常明显。用户发现智能体记得自己的偏好会觉得“这东西真的智能”而不是每次都像第一次见面。4.3 流式输出与前端交互优化现在用户已经习惯了 ChatGPT 那种逐字输出体验Agent 系统如果干等 10 秒一次性返回体验会很糟糕。我基于 SSEServer-Sent Events做了流式输出。FastAPI 实现流式输出的核心逻辑from fastapi.responses import StreamingResponse import json def stream_agent_response(session_id: str, user_message: str): def event_generator(): # 先让智能体慢慢跑每跑完一步就推一个进度事件 yield fdata: {json.dumps({type: status, content: 正在理解你的问题...})}\n\n result agent.run(session_id, user_message) # 把大模型生成的文本逐字推送 for text_chunk in result.stream_answer(): yield fdata: {json.dumps({type: token, content: text_chunk})}\n\n yield fdata: {json.dumps({type: done})}\n\n return StreamingResponse(event_generator(), media_typetext/event-stream) app.post(/api/chat/stream) async def chat_stream(payload: dict): return stream_agent_response(payload[session_id], payload[message])前端用 EventSource 或者 fetch 的 ReadableStream 接收。接口压力测试时发现流式输出对后端吞吐量还有意想不到的好处——客户端数据处理是分块的不会因为单个响应体过大而阻塞连接。5. AI Agent 如何扛住高并发架构与实战5.1 同步调用到异步任务调度这是全篇文章最核心的实战部分。AI Agent 扛并发的关键不是把服务器买大而是把耗时任务从请求链路里摘出来。直接同步调用的链路是这样的用户发请求 → FastAPI 接收 → 调用大模型 API等 6 秒 → 调用工具等 2 秒 → 再调大模型等 3 秒 → 返回结果。这一个请求占用了线程 11 秒期间线程完全被占死。并发量一到 20服务器就基本瘫痪。改用任务队列后的链路变成用户发请求 → FastAPI 接收 → 把任务丢进 Celery 队列 → 立即返回“任务受理成功” → 后台 Worker 慢慢跑完 → 通过 WebSocket 或 SSE 推送结果。前端表现依然是流式接收但后端 Web 进程瞬间释放可以继续接收新请求。我实测过对比数据同步模型下 50 并发就开始大面积超时异步模型下 500 并发依然稳定。这是数量级的差距。5.2 Celery 任务队列与 WebSocket 结果推送具体实现方案如下# celery_app/tasks.py from celery import Celery celery_app Celery( agent_tasks, brokerredis://localhost:6379/0, backendredis://localhost:6379/1 ) celery_app.task(bindTrue, max_retries3) def run_agent_task(self, session_id: str, user_message: str): 后台执行完整的 Agent 流程 try: result agent_graph.invoke({ messages: [{role: user, content: user_message}] }) # 结果推送给前端通过 Redis 发布订阅 redis_client.publish(fagent_result:{session_id}, result) return result except Exception as e: # 重试机制超过重试次数标记失败 self.retry(exce, countdown2 ** self.request.retries)FastAPI 端只需要把任务提交到队列app.post(/api/chat) async def chat(payload: dict): session_id payload[session_id] message payload[user_message] # 创建异步任务 run_agent_task.delay(session_id, message) return {status: accepted, session_id: session_id} app.websocket(/ws/agent/{session_id}) async def websocket_endpoint(websocket: WebSocket, session_id: str): await websocket.accept() # 订阅 Redis 频道等待后台任务结果后推送 pubsub redis_client.pubsub() pubsub.subscribe(fagent_result:{session_id}) for message in pubsub.listen(): if message[type] message: await websocket.send_text(message[data])这套架构里队列起了缓冲的作用。即使某一瞬间涌进 1000 个请求Web 进程只需要快速入队真正耗时的是后台 worker 的数量。高峰期可以临时扩容 worker低峰期缩减弹性伸缩非常方便。5.3 压测方法与关键性能指标上线前压测是必须做的。我分享一下自己的压测流程和分析方法压测工具用 Apache Benchab和 locust。ab 适合单接口压测locust 适合模拟真实用户场景。针对 Agent 服务的压测要注意不要只压 API 接口的 TPS还要关注端到端延迟和成功率。我的压测重点观测四个指标指标健康标准需要注意的信号QPS每秒钟查询量单 worker 下不低于 30低于 10 说明瓶颈在串行链路P95 延迟小于 15 秒超过 20 秒用户会明显感知等待任务成功率不低于 98%低于 95% 说明超时可重试机制有问题Worker 队列积压高峰期积压数能回落持续增长说明 worker 数不足压测中最容易暴露的问题是 Redis 连接池耗尽。Celery 每个 worker 默认保持一个连接但代码里如果直接用了同一个 Redis 连接做发布订阅并发高时会出现连接超时。解决方案是使用连接池并设置合理的最大连接数。另一常见问题是外部 API 限流。Agent 内部要频繁调 DeepSeek API如果你用的是免费额度或低配套餐压测时很容易触发限流。这里一定要实现令牌桶限流 指数退避重试不然上线第一波流量就会把模型 API 打爆。6. 上线部署与持续运营6.1 Docker 容器化部署完整方案项目采用 Docker Compose 编排部署。我贴出实际在用的 docker-compose 配置可以直接作为参考模板version: 3.8 services: api: build: . ports: - 8000:8000 environment: - DATABASE_URLpostgresql://user:passdb:5432/agent - REDIS_URLredis://redis:6379/0 - DEEPSEEK_API_KEY${DEEPSEEK_API_KEY} depends_on: - db - redis deploy: replicas: 3 resources: limits: cpus: 2.0 memory: 4096M worker: build: . command: celery -A celery_app worker --loglevelinfo --concurrency5 environment: - DATABASE_URLpostgresql://user:passdb:5432/agent - REDIS_URLredis://redis:6379/0 - DEEPSEEK_API_KEY${DEEPSEEK_API_KEY} depends_on: - api db: image: pgvector/pgvector:pg16 volumes: - pgdata:/var/lib/postgresql/data environment: - POSTGRES_USERuser - POSTGRES_PASSWORDpass redis: image: redis:7-alpine volumes: - redisdata:/data volumes: pgdata: redisdata:需要注意的几个生产细节API 服务要跑多个副本前面挂 Nginx 做负载均衡。Worker 并发数根据模型 API 限流阈值来设。我压测时发现如果 deepseek 限流是每分钟 500 次每个任务平均调用 3 次模型那 worker 并发设 5 就比较安全。PostgreSQL 是单点故障风险点生产环境务必用云数据库托管或者做主从复制。我踩过数据丢失的坑血的教训。6.2 Nginx 反代配置与多站点域名映射如果同一个服务器上跑不止一个应用Nginx 按域名路由是标准操作。项目上线阶段我用 Nginx 给 Agent 服务配置了反代顺带把同一台服务器上的其他服务用不同域名区分开# 主应用AI Agent 服务 server { listen 80; server_name agent.example.com; location / { proxy_pass http://api:8000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; proxy_read_timeout 120s; # Agent 请求慢读超时一定要拉长 } } # 另一个应用 server { listen 80; server_name blog.example.com; location / { proxy_pass http://blog:3000; } }这里面最容易踩的坑是proxy_read_timeout。默认 60 秒但 Agent 后端有时要等大模型响应就需要更久一旦超时用户收到 504体验极差。我调到 120 秒甚至 180 秒并同时保证异步推送链路空闲时也能正常维持连接。6.3 模型 API 限流与成本控制策略API 成本是运营阶段的大头。记录一下我的成本控制三板斧第一板斧结果缓存。用户问题千奇百怪但有大量重复。比如“退货流程是什么”“怎么退款”这类高频问题直接用 Redis 缓存答案。缓存时对用户输入做个规范化处理解决“退 款”“退款 流程”这类微变体重复调模型的问题。实现缓存后 API 调用量下降了约 30%。第二板斧提示词压缩。每次请求都动态拼上下文内容太长时成本飙升。我在服务层做了一个长度检测超过阈值就启动摘要压缩把旧的上下文用一段摘要替代。这个优化减少大约 20% 的 token 消耗。第三板斧太重。用户主动触发 Agent 完整流程但信息查询类问题默认走“单次调用 工具检索”的轻量路径不启动多步图编排。因为完整 Agent 流程平均要调 3 次大模型轻量路径只要 1 次成本差 3 倍。这个优化在不影响用户体验的前提下省下了最多的钱。7. 常见问题与排查技巧实录7.1 模型输出格式不稳定做 Agent 开发时遇到最多的问题是大模型不按约定输出。尤其使用 Function Calling 时偶尔返回的 JSON 带 Markdown 代码块包裹或者多一个逗号导致 json.loads 直接报错。我的解决方案是写一个鲁棒性强的解析器import json import re def safe_parse_json_response(text: str): 从 LLM 输出中安全提取 JSON # 如果被 Markdown 代码块包裹先去掉 text re.sub(rjson\s*|\s*, , text.strip()) # 尝试直接解析 try: return json.loads(text) except json.JSONDecodeError: pass # 如果失败截取第一个 { 到最后一个 } pattern r\{.*\} match re.search(pattern, text, re.DOTALL) if match: try: return json.loads(match.group()) except json.JSONDecodeError: return None return None这个方法不完美但能救回大部分格式错误场景。真正根治还是要靠重试机制交给模型“你刚才输出格式有误请重新输出合法 JSON”第二三次的成功率极高。7.2 上下文爆炸导致响应变慢运营一段时间后长对话的回话速度越来越慢。定位发现是消息列表太长每次请求消耗的 prompt tokens 越来越多模型处理时间线性增长。解决方式是将历史消息分优先级当前轮次: 完整原文最近 5 轮: 完整原文更早的对话: 定期摘要压缩用户画像与偏好: 结构化数据注入这个逻辑其实就是在记忆管理章节说的那套机制。落实到代码里是每个 session 对象有个 summarize 标记超过 50 条消息就触发一次异步缩减任务。7.3 工具调用失败但智能体不承认模型调用了某个工具但工具返回异常或数据为空此时模型为了讨好用户可能编造结果。比如查询库存失败模型会说“库存充足”而不是“暂时无法获取”。这种幻觉在 Agent 场景比纯聊天更危险因为用户会拿着错误结果去下单。解决办法是从工程上彻底戳破每个工具返回结果都携带一个 success 标记图编排节点根据标记走分支。def safe_tool_executor(name: str, arguments: dict): try: result registry.execute(name, arguments) return {success: True, data: result} except Exception as e: return {success: False, error: str(e)} # 在 LangGraph 节点中失败则标记需要向用户如实说明 def process_tool_result(state): for tool_result in state[tool_results]: if not tool_result[success]: state[should_confess_error] True return state加上这层后智能体遇到工具失败时会如实向用户说“抱歉暂时无法获取到库存信息请稍后再试”而不是一本正经地编数据。这条经验让我避免了很多信任事故。7.4 压测不过性能瓶颈定位方法论如果你压测达不到目标不要盲目加服务器先定位瓶颈在哪一层。我的一套快速定位方法是分层观测Web 层看 FastAPI 进程 CPU 和内存占用。如果 CPU 打满说明 Web 请求堆积考虑加副本。任务层看 Celery Worker 队列积压。如果 Redis 队列长度持续上升说明 Worker 太少增加并发数。外部依赖层看 DeepSeek API 响应时间和限流状态。如果大部分时间都在等待 API 返回需要检查并发数量和请求重试策略。数据库层看 pgvector 查询耗时。向量检索性能不佳时可以添加 HNSW 索引查询速度可提升 10 倍以上。基本上按照这个顺序排查半小时内就能定位主瓶颈。大多数时候瓶颈不在自己写的业务代码而在外部依赖的限流和等待上。8. 上线后的运营数据与迭代方向项目上线后跑了两周观察到的数据是这样的单用户平均会话时长 4 分半工具调用成功率 93%用户满意度问卷评分 4.6/5。这个结果验证了前面所有架构决策的方向是对的。下一步迭代方向我列几个优先级高的本地私有化部署部分企业客户想把自己的数据库接到 Agent 里彻底私有化部署版本已经在做了核心是把模型也切到可私有化的开模型。多模态能力目前的智能体只支持文本交互后续要支持图片输入识别和结果生成技术路线可以是多模态模型加图像工具。人机协同审批流在一些高风险操作批量退款、删除数据前插入审批节点的研究很有必要。这个方向可以参考工具调用机制那套思路给工具执行加一个审批前置条件智能体先把请求提交给管理员确认批准后再真正执行。我个人做完整条链路的体会是AI Agent 开发最难的不是写代码而是工程化兜底。模型层面的能力各家已经拉不开差距拉开差距的是谁把异常处理做得更稳、谁把并发支撑做得更扎实、谁把成本控制得更合理。这篇记录里写的每一个细节都是真实踩过坑之后总结下来的希望能给你的 Agent 项目少走一些弯路。