ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

多模态AI Agent全场景架构实战:FastAPI+LangGraph构建指南

多模态AI Agent全场景架构实战:FastAPI+LangGraph构建指南 Agent AI这块最近两年被聊得太多但真正敢碰“全场景架构”的人不多。大多数文章停留在“用 LangChain 调一次 LLM、写两个工具函数、跑通一个 demo”的阶段等需求变成“多模态输入、高并发、可扩展、多业务复用”的时候框架就塌了。我最近完整落地了一个多模态 Agent 项目走的是 FastAPI LangGraph 统一工具层打通了文本、图片、语音输入也做了一个能扛业务波峰的并发模型。这篇文章不聊虚的直接说架构怎么拆、代码怎么写、并发怎么扛、问题怎么排查。如果你正准备从 0 到 1 搭一个 AI Agent或者已经在做但总觉得哪里拧巴这篇文章应该能帮你省几周的试错时间。1. 先把“多模态交互”彻底想清楚1.1 多模态不是接口堆叠而是认知对齐很多团队做多模态第一步就是把 GPT-4o、Whisper、OCR 全接进来然后发现一个尴尬的问题模型都会调但交互体验极其碎片化。用户先发一张截图再补一句“把这个表格转成 Markdown”Agent 如果先处理文本再处理图片顺序错了意图就丢了。这里的关键不是“能不能处理多种输入”而是“能不能让多种输入在同一套认知框架里对齐”。你可以想象一个场景一个同事既能看图纸又能听讲解但他如果无法把“图纸上的标注”和“你口头说的重点”对应起来那他的“多模态”只是多了两个器官没有形成协同。技术实现上最务实的做法不是自己训练一个多模态大模型而是做输入归一化 统一上下文文本输入直接进 LLM。图片输入走 OCR / 图像描述 / 目标检测把结果转换成结构化文本或描述文本再进 LLM。语音输入走 ASR 转文本同时保留声纹特征用于说话人分离再进 LLM。GUI 操作类输入如用户截图报错把截图转成“界面元素树 坐标 视觉描述”交给 Agent 规划动作。统一上下文的意思是所有模态处理后的结果都写进同一个消息队列由工作流引擎按event_id排序再组装成一次完整的 LLM 请求。这样 Agent 看到的不是“一张图片 一段文字”这样割裂的东西而是“用户在某时刻、带着图片、表达了一个完整意图”的完整事件。1.2 交互协议与状态建模是地基多模态 Agent 的交互复杂不是靠“把 prompt 写长一点”就能解决的。你必须在工程层面定义一套统一的交互协议。我在项目里定义了一个核心数据模型所有模态的输入都收敛到它from pydantic import BaseModel from typing import Optional, List, Literal from enum import Enum class ModalityType(str, Enum): text text image image audio audio gui gui class AgentEvent(BaseModel): event_id: str # 全局唯一用于多模态消息聚合排序 session_id: str # 会话 ID隔离不同用户上下文 modality: ModalityType # 当前事件的模态 content: str # 文本内容 / 图片描述 / ASR 结果 raw_uri: Optional[str] None # 图片、音频的原始文件地址 metadata: Optional[dict] None # 坐标、时长、说话人 ID 等 timestamp: float 0.0 # 客户端时间戳解决乱序问题 class AgentRequest(BaseModel): events: List[AgentEvent] # 一次交互可以携带多个模态事件 user_id: str agent_config: Optional[dict] None这套模型解决了三个问题第一模态无关。无论是语音、图片还是文字到了 Agent 内部统一了结构下游处理逻辑不需要为每种模态写一套入口。第二事件可排序。event_id和timestamp让工作流引擎可以正确处理“用户先发图片后补文字”这类时序场景。第三会话可隔离。session_id是后续所有状态管理、缓存、并发控制的主键。交互状态建模上我强烈建议不要把状态堆在内存里而是按“三层记忆”设计短期记忆当前会话最近 20 轮的核心对话用 token 窗口控制预算。工作记忆当前任务的中间结果比如“用户想要的表格已经转换成 CSV共 15 行”。长期记忆用户偏好、历史知识库条目用向量库持久化。这样做的直接好处是多模态大图、长音频这类高 token 内容不会把短期记忆撑爆而是处理完立刻摘要、入长期记忆腾出空间给真正重要的实时交互。2. 全场景架构设计从单机脚本到可扩展中台2.1 “全场景”到底是全模态还是全业务这个词我聊过不少人发现大家理解的“全场景”完全不是一回事。有的人说的是“文本、语音、图片、GUI 操作都能处理”有的人说的是“客服、办公、代码生成、数据分析、IoT 控制都能干”。这两个目标对架构的要求完全不同。如果你要的是前者核心是把多模态输入处理链路做好模型网关、ASR、OCR、视觉理解这些组件要齐全。如果你要的是后者本质是做一个行业 Agent核心是技能体系、知识库、业务系统对接。我实际踩下来个人和中小团队不要一上来就追“全模态 全业务”。因为 Agent 的能力上限不取决于模型而取决于工具链的完整度和数据的质量。与其做一个啥都能聊但啥都做不好的“万金油”不如把一两个核心场景打穿比如“客服 工单处理”或者“会议纪要素材整理 任务派发”。架构上留好扩展位但业务上先收敛。扩展位怎么做答案是内核统一、场景插件化。内核只负责三件事理解意图LLM 场景提示词模板规划步骤工作流引擎如 LangGraph执行工具统一工具注册中心场景差异全部收敛到“配置 插件”层。新接入一个业务场景不需要改内核代码只需要新增一份场景配置、注册几个业务工具。2.2 架构分层与核心组件基于上面的思路我落地了一套六层架构用一张表说明每层职责分层核心职责关键组件备注接入层多端适配、多模态协议转换REST API、WebSocket、语音网关对外暴露统一接口交互层事件聚合、会话管理、上下文组装Redis Session Store、事件聚合器解决多模态乱序与状态隔离大脑层意图识别、规划、反思、工作流执行LangGraph、LLM Router、Prompt ManagerAgent 的决策中枢工具层工具注册、参数校验、权限管控Tool Registry、函数签名校验器、RBAC所有外部能力统一收口模型层多模型接入、降级策略、Token 预算Model Gateway、模型路由、限流器避免让业务代码直接依赖具体模型基础设施层存储、队列、可观测性、部署PostgreSQL、Redis、RabbitMQ、Prometheus、Docker/K8s生产可用底线为什么要做“中台化”因为当你同时跑三个 Agent 应用——一个客服、一个办公助手、一个数据分析师——你一定会发现它们都在做同样的事调 LLM、管上下文、做工具调用、记日志。如果每个应用各写一套那就是四个字浪费生命。把 Agent 的通用能力抽成独立服务业务方只负责“注册工具 写场景配置”这才是热词里说的“AI Agent 中台”的真正价值。2.3 技术选型FastAPI LangGraph 为什么够用当前最热的技术栈组合是 FastAPI LangChain/LangGraph我实际用下来这个组合的好处非常具体。FastAPI 的异步特性与 Agent 天然匹配。Agent 应用和传统 CRUD 完全不同它是 IO 密集型大部分时间在等 LLM 返回、等工具调用结果异步非阻塞能榨干单机吞吐。LangGraph 比 LangChain 更接近真实 Agent 逻辑。LangChain 的Chain是线性的而真实的 Agent 是带循环、带条件分支、带并行的图结构。LangGraph 用状态机的方式组织节点天然支持“工具调用失败 → 重试 → 换一条路”这类逻辑。Spring AI Agent 适合 Java 团队如果你整个技术栈都是 JVM 生态选它确实能少写点胶水代码。但如果你要频繁改 Agent 逻辑、做实验、灵活编排Python 生态的操作空间大得多。我的选型建议很简单个人练手、小团队快速验证用 FastAPI LangGraph大厂 Java 体系、已有微服务基座用 Spring AI核心团队有能力自研编排引擎的LangGraph 也只是过渡方案。3. 从 0 到 1 搭建多模态 Agent 的最小可运行骨架3.1 工程结构怎么组织很多初学者问 Agent 项目该怎么建目录我直接把我用的结构给你参考agent-project/ ├── app/ │ ├── main.py # FastAPI 入口 │ ├── api/ │ │ └── agent.py # 对外 API 路由 │ ├── core/ │ │ ├── config.py # 配置读取 │ │ ├── model_gateway.py # 模型网关 │ │ ├── session.py # 会话管理 │ │ └── security.py # API 鉴权 │ ├── agents/ │ │ ├── graph.py # LangGraph 工作流定义 │ │ ├── nodes.py # 各节点逻辑意图/工具/回复 │ │ └── prompts.py # 提示词模板管理 │ ├── tools/ │ │ ├── registry.py # 工具注册中心 │ │ ├── weather.py # 示例工具 │ │ └── image_handle.py # 图片处理工具OCR/描述 │ └── middleware/ │ ├── auth.py │ └── metrics.py ├── config/ │ └── config.yaml # 场景配置、模型配置 ├── tests/ │ ├── test_api.py │ └── test_graph.py └── requirements.txt核心设计哲学是路由层只负责接收请求Agent 层只负责决策工具层只负责执行。这样当你把单体改成中台时只需要把工具层和 Agent 层拆成独立服务路由层的改动很小。3.2 核心代码实现LangGraph 工作流工作流我定义了四个节点入口网关 → 意图识别 → 工具执行可循环 → 回复生成。from langgraph.graph import StateGraph, END from typing import TypedDict, List, Optional class AgentState(TypedDict): session_id: str events: list current_intent: Optional[str] tool_results: List[dict] final_response: Optional[str] error: Optional[str] # 节点函数 async def intent_node(state: AgentState): # 调用 LLM 识别用户当前意图 prompt build_intent_prompt(state[events]) intent await llm_call(prompt, temperature0.1) return {current_intent: intent} async def tool_exec_node(state: AgentState): intent state[current_intent] tool_name parse_tool_name(intent) args parse_tool_args(intent) if not tool_name: return {tool_results: [], error: None} result await execute_tool(tool_name, args, state[session_id]) return {tool_results: state[tool_results] [result]} async def should_continue(state: AgentState): # 判断是否需要继续调用工具或进入回复生成 if state.get(error) or not state.get(tool_results): return generate return tool if needs_more_tools(state) else generate async def generate_node(state: AgentState): response await llm_call(build_response_prompt(state)) return {final_response: response} # 构建图 def build_agent_graph(): graph StateGraph(AgentState) graph.add_node(intent, intent_node) graph.add_node(tool, tool_exec_node) graph.add_node(generate, generate_node) graph.set_entry_point(intent) graph.add_edge(intent, tool) graph.add_conditional_edges(tool, should_continue, {tool: tool, generate: generate}) graph.add_edge(generate, END) return graph.compile()这张图的核心价值是把“循环”显式表达出来了。真实业务里 Agent 经常需要连续调用多个工具比如查天气后查交通再定餐厅LangGraph 的条件路由让这种编排变得自然。这里要注意一个坑一定要设置迭代上限。我在tool节点前加了一个步数检查超过 5 次工具调用直接强制进入生成节点。否则 Agent 可能在“工具返回结果不符合预期”时无限重试Token 费用让你哭都来不及。3.3 工具注册机制工具层我用的最简单可靠的方案“装饰器 全局注册表”。# tools/registry.py from typing import Callable, Dict, Any import inspect _TOOL_REGISTRY: Dict[str, Dict[str, Any]] {} def register_tool(name: str, description: str, schema: dict): def decorator(func: Callable): _TOOL_REGISTRY[name] { name: name, description: description, schema: schema, # JSON Schema校验参数 func: func, } return func return decorator def get_tool(name: str): if name not in _TOOL_REGISTRY: raise ValueError(fTool {name} not registered) return _TOOL_REGISTRY[name][func] def list_tools() - list: # 这个列表会直接注入到 LLM 的 system prompt 里让模型知道有哪些工具可用 return [ {name: t[name], description: t[description], schema: t[schema]} for t in _TOOL_REGISTRY.values() ]使用示例# tools/image_handle.py from .registry import register_tool register_tool( nameextract_table_from_image, description从含表格的图片中提取结构化数据返回 Markdown 表格, schema{ type: object, properties: { image_uri: {type: string, description: 图片地址} }, required: [image_uri] } ) async def extract_table_from_image(image_uri: str): # 实际走 OCR 表格结构识别 return | 列1 | 列2 |\n| --- | --- |\n| 数据1 | 数据2 |这套注册机制的好处是扩展新工具时完全不碰 Agent 核心代码业务方只要往工具包里加函数就行中台化的时候非常顺畅。3.4 模型网关别让业务代码直接绑 LLM模型网关是很多人忽略的组件。当你的 Agent 要调用多种模型——ASR 用小模型、OCR 用专用模型、核心对话用 128K 上下文的大模型、轻量意图识别用快速小模型——你不可能在每个业务节点里直接写“调 OpenAI”或者“调某云厂商”。我定义了一个模型网关接口# core/model_gateway.py import os import httpx from typing import Optional, List class ModelGateway: 统一模型网关负责路由、降级、超时控制 def __init__(self, config: dict): self.default_model config[default_model] self.fallback_model config[fallback_model] self.timeout config.get(timeout, 30) async def chat(self, messages: List[dict], model: Optional[str] None, **kwargs): model model or self.default_model try: return await self._call_llm(messages, model, **kwargs) except TimeoutError: # 大模型超时降级到小模型 return await self._call_llm(messages, self.fallback_model, **kwargs) async def _call_llm(self, messages, model, **kwargs): # 这里按实际模型服务商的 SDK 接入 pass在 LangGraph 的所有节点里只调用gateway.chat()不直接访问模型服务。这样后续换模型商、加本地模型、调整策略只改网关内部实现。加粗提醒一句网关层必须记录每个请求的 token 用量和响应延迟不然后面做成本核算和性能调优的时候寸步难移。4. AI Agent 怎么扛并发性能与稳定性实战4.1 先把并发瓶颈想清楚“AI Agent 怎么扛并发”这个热词搜索量很高但大部分人问错了问题。Agent 的并发瓶颈根本不是常规后端项目那种“数据库连接池满了”“慢 SQL 拖垮 CPU”而是一个更扎心的现实LLM 单次调用的耗时是以秒计的而你不可能无限扩容模型服务。假设你的 Agent 每轮完整交互需要调 3 次 LLM意图识别、工具决策、回复生成每次平均 2 秒那么单个请求的端到端耗时保底 6 秒。如果你期望支撑 100 QPS意味着同一时刻最多可能有 600 个请求在执行。这还只是 LLM 本身没算工具调用、文本向量化这些额外开销。用个类比常规后端项目就像一个小卖部每个顾客付款只要几秒你请三个收银员就能忙过来。Agent 项目像一个银行柜台每笔业务要二三十分钟再多的收银员也不会让单笔业务变快你只能开多个窗口、排好队、别让人插队。所以并发方案的核心就三个字削峰、分流、保障质量。4.2 接入层限流 业务层排队 模型层池化不能把“进来一个请求就同步发一次 LLM 调用”这种简单做法直接上生产。我在项目中做了三层管控第一层接入层限流。部署一个令牌桶按用户维度限流防止单一用户刷爆模型额度。from slowapi import Limiter from slowapi.util import get_remote_address limiter Limiter(key_funcget_remote_address) app.post(/api/agent) limiter.limit(30/minute) async def agent_api(request: AgentRequest): return await run_agent(request)第二层业务层排队。因为 LLM 并发有硬上限超出上限的请求必须排队。我用 Redis 列表做了一个简单的 FIFO 队列import redis import asyncio import json r redis.Redis(hostredis, port6379, db0) async def enqueue_task(session_id: str, events: list): task {session_id: session_id, events: events} await r.rpush(agent_queue, json.dumps(task)) async def worker_loop(): while True: _, raw_task await r.blpop(agent_queue) task json.loads(raw_task) # 从队列里拿出来的任务走 LangGraph 完整流程 await run_agent_workflow(task[session_id], task[events])第三层模型层池化。对同一个模型服务商维护多个 API Key用轮询或并发量分配避免单 Key 触发限流。同时对 HTTP 连接做连接池复用避免频繁建连。这个方案实测下来100 QPS 的波峰能被平滑到模型供应商配额以内不会出现“偶发 429 导致大量任务失败”的情况。4.3 缓存策略该省的坚决省LLM 调用是最贵的能缓存就缓存。但缓存的粒度要想清楚。我总结了三类可缓存场景意图识别缓存相同或相似的用户输入意图一般不会变。用 embedding 相似度做输入向量缓存命中就直接走预定义分支。工具结果缓存查天气、查汇率、查商品信息这类工具返回变化不频繁可以缓存 5 分钟到 1 小时。完整回复模板缓存常见 FAQ 类问题直接命中预设答案完全不用走 LLM。缓存键的设计要注意必须包含 session 的个性化偏好否则不同用户拿到完全一样的回复体验会很差。我在做推荐类任务时缓存键是user_id 意图 推荐候选词列表的哈希。降级策略也必须提前写大模型超时第 1 次 → 自动切换同厂商更快的小模型。小模型也失败 → 返回“当前服务繁忙”并记录上下文让用户稍后重试。关键工具失败 → 不走循环重试直接给出“部分结果 提示”。使用优先级从高到低缓存 模板 小模型 大模型 温和报错。4.4 可观测性没有监控的并发方案都是裸奔Agent 应用的监控比传统后端更复杂除了常规的 QPS、延迟、错误率你还需要追踪Token 消耗趋势按用户、按会话维度防止单用户耗尽预算。工具调用成功率哪个工具在拖后腿一查便知。规划路径每条请求走了哪些节点、循环了几次用 trace ID 串起来。模型降级率降级太多说明主模型稳定性有问题。我落地时在 FastAPI 的 middleware 里加了一行 response headerX-Trace-ID每个请求的完整链路日志都带这个 ID排查问题时按 ID 一拉到底。app.middleware(http) async def add_trace_id(request, call_next): trace_id uuid.uuid4().hex request.state.trace_id trace_id response await call_next(request) response.headers[X-Trace-ID] trace_id return response日志里记录意图识别结果、工具调用参数、LLM 响应的 token 数、节点耗时。这套数据跑起来之后你会发现很多问题根本不用“猜”看一眼链路图就知道卡在哪一环。5. 常见问题与排查技巧实录5.1 多模态消息的“时序错乱”问题真实场景里用户可能先按住说话说到一半又掏出一张截图补发。两个消息到达服务端的时间顺序很可能和用户真实意图相反。我第一次上线时就翻过车用户语音说“把这个表格改成柱状图”随后发了表格截图但服务端先处理了截图Agent 看到一张没有上下文的图片回复“这是一张表格图片请问需要我做什么”用户当场骂街。解决方案是事件聚合器。按session_id分组缓存最近 500ms 内到达的多个事件等窗口关闭后再一次性组装成AgentRequest发送给工作流。如果等待期间收到了连续多个事件还可以按时间戳重新排序。这个 500ms 的窗口值不是拍脑袋定的我测试过低于 200ms 聚合效果差高于 1000ms 用户体验有明显卡顿感。5.2 Agent 在工具调用上“死循环”Token 蹭蹭涨LangGraph 这类状态图最强的地方是“循环”最危险的地方也是循环。一个典型的翻车场景用户要求“查询订单状态”订单系统返回“未找到”Agent 的反思节点认为“可能是查询参数不对”于是换个姿势再查再失败再换。如果不限制最大迭代数一次请求可能烧掉几十万 Token。我的解法粗暴但有效系统级硬限制 循环内容摘要。MAX_TOOL_CALLS 5 async def tool_exec_node(state: AgentState): if state[tool_calls_count] MAX_TOOL_CALLS: state[error] max_tool_calls_exceeded return state ...同时每次工具调用的原始结果不再全量塞进上下文而是做一个摘要原始结果 3000 字摘要成 150 字只保留关键数据和失败原因。这样即使循环重试Token 预算也完全可控。5.3 上下文污染多模态大内容把指令挤跑了当用户发来一张 2MB 的截图OCR 出来可能是一千多行文本其中可能还夹杂着表格坐标、页面结构等辅助信息。如果把这些全塞进 context你会发现 Agent 开始“失忆”连前面约好的“只输出 Markdown 格式”都忘掉了。这不是模型笨是上下文窗口被低频信息占满了system prompt 里的核心指令被挤出了注意力范围。处理原则是“分块管理上下文窗口”system prompt 永远在窗口头部不受影响。多模态处理结果先走摘要默认最多 500 字。历史对话按重要性保留超过 20 轮就滚动压缩。关键用户参数时区、偏好、格式要求固定在 context 末尾并做语法标记。我在 prompt 模板里加了一行“关键约定区”每次都动态填充确保模型回复时永远能看到。5.4 并发场景下的会话状态错乱并发一上来最先崩的就是内存态会话管理。两个请求同时到达第二个请求读到的上下文可能是第一个请求写到一半的脏数据。血的教训状态别放内存全量放 Redis并且用 session_id 作为唯一锁粒度。async def get_session_state(session_id: str): raw await r.get(fsession:{session_id}) return json.loads(raw) if raw else {history: [], pending_tools: []} async def save_session_state(session_id: str, state: dict): await r.set(fsession:{session_id}, json.dumps(state), ex3600)对于“同 session 并发请求”我用分布式锁保证同一时刻只有一个 Agent 工作流在写状态另一个请求排队或直接返回“上一个任务还在处理中”。5.5 问题排查速查表现象可能原因排查思路解决方案多模态消息处理顺序乱了事件聚合窗口太短查看 trace 日志中的事件时间戳调大聚合窗口至 500ms回复内容驴唇不对马嘴上下文被大图/长音频污染检查 context 中摘要占比限制多模态转文本的最大长度Token 消耗异常飙升工具死循环或重试次数太多查 graph 节点循环数设置最大步数 结果摘要高并发下大量 429 错误单 API Key 触达限流查模型网关日志多 Key 轮换 业务层排队用户 A 看到用户 B 的数据缓存键没有带 session/用户维度查缓存记录缓存键加上 user_id请求超时工具调用没有超时控制查工具层耗时每个工具强制设置 5s 超时6. 学习路线与练手项目建议6.1 三类适合个人练手的多模态 Agent 项目如果你想快速入门不要上来就做“全能助手”做一个小而完整的真实项目收获更大。第一个是图文混合客服助手。用户发“这个商品怎么用” 商品说明书截图Agent 需要先 OCR 识别说明书再结合商品库信息回答。这个项目覆盖了多模态输入、工具调用、RAG 检索三个核心点一周左右能跑通。第二个是会议纪要 Agent。输入一段 30 分钟的录音Agent 做 ASR、说话人分离、要点提取、任务分配建议、日历日程创建。这个项目的难点在长音频的分段处理和时间轴对齐做完你会对“异步任务”和“事件驱动”理解得特别深。第三个是数据分析 Agent。用户上传 CSV 或数据库连接串用自然语言问“哪个地区销量下滑最严重”Agent 需要生成 pandas 代码、执行、读结果、再回答。这个项目重点练“工具返回值如何反馈给 LLM 再生成一次答案”的闭环。6.2 学习路线按节奏递进别一口吃成胖子根据复盘我建议的学习路线分五个阶段每阶段都有一个明确产出第一阶段掌握基础调用。会用 OpenAI SDK 调接口、会用 Pydantic 做结构化输出。产出一个能根据用户指令返回结构化 JSON 的小工具。第二阶段学会工具调用。理解 Function Calling 原理自己注册 3 个工具让模型自主决定调用谁。产出一个“天气 穿衣建议”小助手。第三阶段掌握工作流编排。用 LangGraph 实现条件分支、循环、并行。产出一个能自动查资料、总结、写邮件并发送的 Agent。第四阶段打通多模态。接入 ASR 和 OCR把语音和图片统一成事件模型。产出一个图文混合问答机器人。第五阶段做生产级改造。加限流、缓存、Docker 部署、监控告警。产出一个能扛住线上流量的小型 Agent 服务。每一阶段不要跳也别停留太久。第三阶段是最多人卡住的核心原因是“你以为你在编排工作流其实你在写面条代码”。如果你发现自己写的图节点之间耦合严重、改一个节点要动三个文件说明你还没理解“数据流驱动”的精髓——每个节点只读外部传入的状态只改自己的输出。6.3 一个善意的提醒热词里有一条“个人使用 AI Agent 做期货交易”我能理解大家为什么对这个感兴趣但从技术角度我必须负责任地说当前 Agent 在金融交易里最大的问题不是“能不能执行”而是“无法为不可控风险负责”。期货交易涉及高杠杆、强时效、尾盘流动性极差等场景Agent 的一个工具误判或模型幻觉造成的损失是实际且不可逆的。即便技术上能跑通一个自动下单的 Agent也强烈不建议在没有严格风控体系和长期模拟验证的情况下实盘。这是一条经验之谈不是泼冷水。7. 一些真实的体会多模态 Agent 做了几轮之后我最大的感受是难点从来不在模型而在工程确定性。模型能力早就够了难的是如何让图片、语音、文本在同一条时间线上对齐难的是如何让 Agent 在工具调用失败时知进退难的是如何在高并发下控制成本、保证延迟顺畅。这些都不是靠“调 prompt”能解决的需要架构层面的设计。最后分享一个小技巧。做 Agent 项目时很多人写的 system prompt 是静态的但我强烈建议把 system prompt 变成“函数式生成”——根据当前会话场景、用户偏好、可用工具列表动态拼接。这样同样的 Agent 内核在不同场景下表现完全不同这才是“全场景”的真正实现方式。这个方向后续还能继续展开的方向不少比如多 Agent 协作、Agent 自建任务队列、基于反馈的自动优化每条都值得单独写一篇。先把这个基础框架吃透后面会轻松很多。
返回列表