带你实现一个Agent(下),从记忆系统、ReAct到具体案例
前面我们想要实现一个简单的Manus也就是带着大家实操做一个Agent出来只不过篇幅确实太大所以分成了上下两篇今天是第二篇核心是记忆系统、ReAct框架与一个小红书爆款实践案例。记忆系统真正做过复杂AI项目的同学都会理解在AI应用层最难的其实是数据如何与AI做交互。比如我看过几个生产级复杂AI项目代码量就1万行左右但所依赖知识库却大的惊人这里伴有强烈的非对称性其结果是复杂AI项目80%的时间都在处理数据问题因此我们会对于复杂AI项目中AI如何与数据交互的范式最佳实践是特别关注的也就是在这个基础下出了很多名词短期记忆、长期记忆、语义记忆、情景记忆…所有这一切构成了Agent的记忆系统。如果说 LLM是 Agent 的大脑负责思考和决策那么 Memory 就是 Agent 的海马体负责记录经验和知识。LLM 的核心特性是无状态。对模型来说每一次调用都是全新的开始。无论你们之前聊得多么热火朝天一旦开启新的一轮对话它就把前面发生的一切忘得干干净净。为了让 Agent 具有“记忆”就需要构建一套外部记忆系统。这套系统不仅仅是简单的“把聊天记录存下来”它需要解决三个核心工程挑战记在哪里存储机制数据库 selection怎么记住写入策略Short-term vs Long-term怎么想起检索机制RAG Retrieval在工程语境下Memory 指的是模型在当前输入之外仍然能够访问和使用的信息集合。这些信息可能来自历史对话、外部存储或系统内部状态但核心目标只有一个为当前推理提供必要的上下文补充。从内容性质上看Agent 中的记忆通常可以分为三类情景记忆记录具体发生过的事件或会话片段例如用户说过的话、一次任务中的中间决策过程。语义记忆记录抽象后的稳定信息例如用户偏好、确认过的事实、总结后的结论。程序性记忆记录“如何做事”例如工具、技能、流程模板或固定执行策略。这是一种逻辑分类并不等同于具体的存储或实现方式。真正落地时这些记忆往往会以不同工程形态存在。最后要注意的是记忆系统是整个Agent最复杂、金贵的部分我们这里只会给出最简单的介绍系统性的介绍还是得上课unsetunset常见的 Memoryunsetunset在实际系统中很少直接实现抽象的“情景记忆”或“语义记忆”而是通过几种常见的工程模式来承载它们上下文记忆上下文记忆是最基础的实现方式其是将历史对话原样拼接到当前 Prompt 中一并发送给模型模型通过看到之前的对话内容保持语义连贯性。这种方式实现成本极低适合原型验证或短对话场景但受限于模型的 Token 上限对话越长成本越高也无法支持跨会话或长期记忆。从本质上看它是一种短期、一次性的情景记忆。滑动窗口记忆滑动窗口记忆是在上下文记忆基础上的一种约束策略只保留最近固定轮数的对话其余内容直接丢弃。它解决的不是“记忆能力”问题而是“Token 成本控制”问题。在工程上可以理解为情景记忆的生命周期管理机制。它适合上下文有效期明确、业务流程较短的场景但一旦关键信息被滑出窗口就会永久丢失。摘要记忆摘要记忆通过调用模型对历史对话进行压缩将大量情景记忆转换为一段简要描述并在后续对话中使用该摘要替代原始内容。这种方式在成本和上下文长度上具有明显优势但摘要不可避免造成信息丢失质量高度依赖模型能力。因此它更适合保留“整体脉络”而不适合依赖精确细节的场景。从记忆类型上看摘要记忆本质上是将情景记忆转化为低精度的语义记忆。向量记忆向量记忆是一种典型的长期记忆实现方式。其核心做法是将对话内容、经验或用户偏好向量化后存入向量数据库在需要时通过语义相似度检索相关内容。这种方式不受对话长度限制适合长期知识积累和跨会话记忆但检索结果是“语义相似”而非“精确匹配”实现复杂度高于前几种方式。它是当前 Agent 系统中最常见的语义记忆工程实现。记忆存储有些信息是需要存储起来的这有很多目的保存一次会话内的对话历史支持在同一会话中多轮交互AI 能访问历史消息保证消息顺序和完整性提供高效的查询与加载机制支持语义检索根据需求和项目复杂度通常涉及以下几类存储关系型数据库。结构化存储、查询方便、成熟稳定、ACID事务支持本地 JSON 文件。无需数据库操作简单方便保存和读取整个会话向量数据库。支持高维向量存储与相似度检索语义搜索方案优点缺点适用场景MySQL / PostgreSQL强大稳定高并发部署维护成本高生产级服务SQLite单文件零配置SQL 支持全并发弱适合单机本地 Agent / 实验 / 轻量应用本地 JSON 文件极致简单无法复杂查询读写效率低脚本级测试向量数据库语义检索能力只能存向量不适合存结构化业务数据长期记忆 / 知识库我们后续的存储方式是SQLite ChromaDB关键连接RAGSQLite ChromaDB 的混合存储方案相当于给 Agent 配备了硬盘。RAG在Agent记忆系统中扮演了关键角色。它的核心职责是在有限的上下文窗口内精准地加载最相关的长期记忆。对于 Memory 模块RAG 不仅仅是“搜索”它包含了一个完整的记忆调度流程感知当用户说话时系统不仅将其视为输入还将其视为“检索 query”。回忆拿着 query 去 ChromaDB语义联想和 SQLite精确查询中寻找相关片段。筛选只保留最重要、最相关的信息受 Token 限制不能全塞进去。注入将筛选出的记忆片段格式化如 System Prompt: 相关历史…塞入当前对话的 Prompt 中。通过 RAG解决了 Agent 记不住无状态和记不下Token 限制的矛盾。接下来是具体实现unsetunset基于双存储的 Memory 系统unsetunset为了实现上述目标解决Agent记不住、存不下的问题我们设计了一个分层的 Memory 架构L1 热记忆载体内存 / List内容当前会话最近 N 轮对话。特点极快原汁原味但容量极小滑动窗口。作用保持当前对话的连贯性L2 温记忆载体ChromaDB内容历史对话的 Embedding 向量 摘要。特点容量大支持模糊语义检索。作用提供长期经验和背景知识如“你三个月前提到喜欢吃辣”。L3 冷记忆载体SQLite内容完整的结构化会话日志Session/Messages。特点即便系统重启也不丢失支持精确 SQL 查询。作用作为“单一事实来源Source of Truth”用于审计、回溯或重建向量库。整体流程如下用户输入 - RAG 检索引擎RAG 引擎 - 并行查询 (L1 热记忆 L2 温记忆)结果融合 - 构建完整的 PromptLLM 生成回复异步写入 - 同时更新 L1滑动窗口、L2向量库、L3数据库unsetunset写入与管理机制unsetunset在写代码之前最后需要明确的是“怎么管”这些数据我们需要制定以下核心策略一、双写一致性策略我们既有 SQLite 又有 ChromaDB如何保证它们数据不打架以 SQLite 为主所有的原始数据Message首先写入 SQLite生成唯一的 message_id。以 ChromaDB 为辅将 SQLite 中的文本向量化后存入 ChromaDB并在 Metadata 中记录对应的 message_id。关联查询检索时先从 ChromaDB 找到相似向量获取 message_id再可选地回查 SQLite 获取完整详情。这确保了向量库只是一个“索引”而不会变成数据孤岛。二、混合检索策略为了避免检索出完全不相关的内容我们需要给检索加“围栏”用户隔离检索时必须强制带上 user_id 过滤条件防止 A 用户查到 B 用户的隐私。阈值过滤设置相似度阈值如 0.4如果最相关的记忆相似度都很低说明这是个新话题直接不注入任何长期记忆避免产生幻觉。三、生命周期管理滑动窗口L1 热记忆只保留最近 10-20 轮。持久化L2 和 L3 必须落盘确保服务重启后“失忆”不会发生。衰减可选虽然本期暂不实现复杂的艾宾浩斯遗忘曲线但在设计表结构时我们预留了 importance_score重要性评分和 last_accessed_at最后访问时间为未来实现“不常用的记忆自动淡化”打好基础。至此就可以开始代码实现了unsetunset实现记忆系统unsetunset基于前面的理论基础我们实现了一个完整的记忆系统包含数据存储、向量检索、RAG 增强和 LLM 交互等核心功能。整个系统采用分层架构从底层到上层依次为应用层: chat_with_memory.py (LLM 交互入口) ↓ 工具层: memory_tools.py (高级封装) ↓ 服务层: memory_service.py (业务逻辑) ↓ 存储层: vector_store.py models.py (数据访问) ↓ 数据层: ChromaDB SQLite (实际存储)这里的设计原则是分层解耦每层只依赖下一层便于测试和替换面向接口通过抽象接口而非具体实现编程单一职责每个模块只负责一个明确的功能域数据模型设计一、users表用户class User(Base): id Column(Integer, primary_keyTrue) username Column(String(100), uniqueTrue, nullableFalse) email Column(String(255), uniqueTrue, nullableTrue) created_at Column(DateTime, defaultdatetime.utcnow) updated_at Column(DateTime, defaultdatetime.utcnow)二、sessions 表会话class Session(Base): id Column(Integer, primary_keyTrue) session_id Column(String(100), uniqueTrue, nullableFalse) user_id Column(Integer, ForeignKey(users.id)) title Column(String(255), nullableTrue) context_window Column(Integer, default10) # 上下文窗口大小 is_active Column(Boolean, defaultTrue) created_at Column(DateTime, defaultdatetime.utcnow)三、memories 表记忆class Memory(Base): id Column(Integer, primary_keyTrue) user_id Column(Integer, ForeignKey(users.id)) session_id Column(Integer, ForeignKey(sessions.id), nullableTrue) memory_type Column(String(50)) # episodic/semantic/procedural content Column(Text, nullableFalse) metadata Column(JSON, nullableTrue) vector_id Column(String(100)) # ChromaDB 向量ID importance_score Column(Float, default0.5) # 重要性评分 access_count Column(Integer, default0) # 访问次数 last_accessed_at Column(DateTime, nullableTrue) is_deleted Column(Boolean, defaultFalse) # 软删除设计要点memory_type 区分三种记忆类型vector_id 关联向量数据库importance_score 用于记忆过滤和排序access_count 支持热度分析is_deleted 实现软删除避免误删向量存储实现使用 ChromaDB 作为向量数据库核心代码如下class VectorStore: def __init__(self, persist_directory: str ./chat_chroma.db): self.client chromadb.Client(Settings( persist_directorypersist_directory, anonymized_telemetryFalse )) self.collection self.client.get_or_create_collection( namememory_collection ) def add_memory(self, content: str, metadata: Dict None) - str: 添加记忆到向量库 memory_id str(uuid.uuid4()) metadata metadata or {} metadata[created_at] datetime.utcnow().isoformat() self.collection.add( ids[memory_id], documents[content], metadatas[metadata] ) return memory_id def search_memories(self, query: str, n_results: int 5, filter_metadata: Dict None) - Dict: 语义搜索记忆 results self.collection.query( query_texts[query], n_resultsn_results, wherefilter_metadata ) return { ids: results[ids][0], documents: results[documents][0], metadatas: results[metadatas][0], distances: results[distances][0] }关键特性本地持久化无需额外服务数据保存在本地自动嵌入ChromaDB 内置嵌入模型自动向量化元数据过滤支持通过元数据精确过滤语义搜索基于余弦相似度的向量检索记忆服务层MemoryService 整合了数据库和向量库提供统一的记忆管理接口。核心方法包括添加记忆双写机制def add_memory(self, user_id: int, content: str, memory_type: str episodic, session_id: int None, metadata: Dict None, importance_score: float 0.5) - Memory: 添加记忆同时保存到数据库和向量库 db self._get_db_session() try: # 1. 创建数据库记录 memory Memory( user_iduser_id, session_idsession_id, memory_typememory_type, contentcontent, metadatametadata or {}, importance_scoreimportance_score ) db.add(memory) db.commit() db.refresh(memory) # 2. 添加到向量库 vector_metadata { user_id: user_id, memory_type: memory_type, memory_db_id: memory.id } vector_id self.vector_store.add_memory( contentcontent, metadatavector_metadata ) # 3. 更新向量ID memory.vector_id vector_id db.commit() return memory finally: db.close()搜索记忆语义检索 数据库查询def search_memories(self, query: str, user_id: int None, memory_type: str None, n_results: int 5) - List[Dict]: 搜索记忆 # 1. 向量搜索 filter_metadata {} if user_id: filter_metadata[user_id] user_id if memory_type: filter_metadata[memory_type] memory_type results self.vector_store.search_memories( queryquery, n_resultsn_results * 2, filter_metadatafilter_metadata if filter_metadata else None ) # 2. 整合数据库信息 memories [] db self._get_db_session() try: for i, vector_id in enumerate(results[ids]): metadata results[metadatas][i] memory_db_id metadata.get(memory_db_id) if memory_db_id: memory db.query(Memory).filter( Memory.id memory_db_id, Memory.is_deleted False ).first() if memory: # 更新访问统计 memory.access_count 1 memory.last_accessed_at datetime.utcnow() memories.append({ id: memory.id, content: memory.content, memory_type: memory.memory_type, importance_score: memory.importance_score, distance: results[distances][i], created_at: memory.created_at.isoformat() }) if len(memories) n_results: break db.commit() return memories finally: db.close()核心逻辑双写机制同时写入 SQLite 和 ChromaDB关联查询通过 memory_db_id 关联两个存储访问统计每次检索自动更新访问计数软删除过滤自动过滤已删除记忆高级工具层MemoryTools 提供面向应用的高级接口最核心的是 RAG 检索功能def retrieve_for_query(self, user_id: int, query: str, session_id: int None, include_context_window: bool True, max_results: int 5) - Dict: RAG 检索整合短期和长期记忆 result { context_window: [], relevant_memories: [] } # 1. 获取上下文窗口短期记忆 if include_context_window and session_id: context_memories self.service.get_context_window(session_id) result[context_window] [ {content: m.content, created_at: m.created_at.isoformat()} for m in context_memories ] # 2. 语义搜索长期记忆 relevant self.service.search_memories( queryquery, user_iduser_id, n_resultsmax_results ) result[relevant_memories] relevant return resultRAG 实现要点双重检索同时获取短期上下文窗口和长期向量检索记忆智能拼接按照系统提示 → 长期记忆 → 短期记忆 → 当前查询的顺序组织数量控制限制每部分的记忆数量避免超出 Token 限制ChatWithMemory 类整合了记忆系统和 LLM 调用class ChatWithMemory: def chat(self, user_input: str, use_rag: bool True) - str: 与 LLM 聊天带记忆 messages [{role: system, content: self.system_prompt}] if use_rag: # RAG 检索 rag_result self.memory.retrieve_for_query( user_idself.user_id, queryuser_input, session_idself.session_id, include_context_windowTrue, max_results3 ) # 添加相关长期记忆 if rag_result[relevant_memories]: memory_context 相关历史信息/n for mem in rag_result[relevant_memories][:3]: memory_context f- {mem[content]}/n messages.append({role: system, content: memory_context}) # 添加上下文窗口 for ctx in rag_result[context_window]: # 解析对话内容 ifUser:in ctx[content] and Assistant:in ctx[content]: parts ctx[content].split(/nAssistant:) user_part parts[0].replace(User:, ).strip() assistant_part parts[1].strip() messages.append({role: user, content: user_part}) messages.append({role: assistant, content: assistant_part}) # 当前输入 messages.append({role: user, content: user_input}) # 调用 LLM response call_llm(messagesmessages) assistant_message response.choices[0].message.content # 保存对话记忆 self.memory.add_conversation_memory( user_idself.user_id, session_idself.session_id, user_messageuser_input, assistant_messageassistant_message ) return assistant_message完整流程检索记忆使用 RAG 获取相关历史信息构建消息按照 OpenAI 格式组织对话历史调用 LLM发送给模型生成回复保存记忆将本轮对话保存到记忆系统使用示例# 基础使用 from memory_tools import MemoryTools # 初始化 memory MemoryTools() # 创建用户和会话 user_id memory.create_user(alice) session_id memory.create_session(user_id, session-001) # 添加对话记忆 memory.add_conversation_memory( user_iduser_id, session_idsession_id, user_message我喜欢Python编程, assistant_messagePython是一门很棒的语言 ) # 搜索记忆 results memory.search_memories( user_iduser_id, query编程语言, n_results5 )带记忆的聊天# 运行交互式聊天 python chat_with_memory.py # 示例对话 你: 我叫Alice喜欢编程 助手: 你好Alice很高兴认识你。编程是一个很有趣的领域... 你: 我之前说过我叫什么名字 助手: 你之前说你叫Alice。系统会自动保存每轮对话到记忆系统检索相关历史信息将记忆注入到 LLM 的上下文中小结这个记忆系统的实现展示了如何将理论概念转化为可用的工程系统分层架构清晰的职责划分便于维护和扩展双存储设计关系数据库 向量数据库各司其职RAG 实现整合短期和长期记忆提供完整上下文实用工具从底层 API 到高级封装满足不同需求通过这套系统Agent 可以记住用户的偏好和历史对话在长期对话中保持上下文连贯性基于历史经验提供个性化回答跨会话复用知识和技能这正是 Memory 在 Agent 系统中的核心价值所在。unsetunsetReAct任务规划unsetunset在了解记忆系统后便可进入ReAct框架模块了说白了就是如何循环生成任务规划。任务规划Planning是 Agent 系统中的核心控制模块负责将复杂的自然语言指令转化为结构化的可执行步骤。它连接了LLM的推理能力与工具Tools的执行能力通过“先规划、后执行”的模式解决直接生成执行动作带来的不确定性与幻觉问题。PS只不过这个想法很好事实上在Skills之前不稳定性挺高的ReAct的核心模块包含三个组件Planner规划器负责调用 LLM 生成结构化计划JSON。Executor执行器负责解析计划按序调度工具并管理上下文数据的流转。Data Model数据模型定义标准的计划与步骤结构作为各组件间的契约。这个东西其实复杂度不高就一个循环罢了我们直接上代码实现数据模型定义系统通过 Plan 和 PlanStep 类定义标准的数据结构。每个步骤包含唯一的 ID、工具名称、参数以及执行状态。dataclass class PlanStep: id: str tool: str args: Dict[str, Any] why: str status: Literal[pending, running, success, failed, skipped] pending output: Any None error: str dataclass class Plan: goal: str steps: List[PlanStep] field(default_factorylist)规划器设计规划器通过 System Prompt 强制 LLM 输出 JSON 格式并注入当前可用的工具描述。为了实现步骤间的数据传递我们定义了模板语法 {{steps.step_id.output.field}}允许后续步骤引用前序步骤的输出system_prompt f 你是一个任务规划器Planner。你必须只输出 JSON不要输出任何解释文字。 目标把用户的需求拆成若干步每一步要调用一个工具tool并提供参数args。 关键规则——数据依赖 如果某一步的 args 需要依赖前面步骤的输出结果请务必使用模板语法 {{{{steps.前面的步骤ID.output.字段名}}}}。 不要自己捏造数据而是引用前序步骤的输出。 例如 1. **step1 (ids1) 调用 geocode 返回 {{location: 116.40,39.90}}** 2. **step2 (ids2) 需要用到这个坐标args 应该写 {{location: {{{{steps.s1.output.location}}}}}}** 你必须输出的 JSON 结构 {{ goal: ..., steps: [ {{ id: step1, tool: tool_name, args: {{ ... }} }} ] }} 执行器与参数解析执行器在调用工具前会先扫描参数中的模板占位符并从当前的执行上下文Context中提取真实值进行替换。这种机制实现了模型规划与具体数据处理的解耦async def _run_step(self, step: PlanStep, mcp_client: Client, context: Dict[str, Any]) - None: step.status running try: # 解析参数中的 {{...}} 模板替换为上下文中的真实数据 resolved_args resolve_templates(step.args, context) # 调用 MCP 工具 result await mcp_client.call_tool(step.tool, resolved_args) # 记录输出结果 step.output getattr(result, structured_content, None) or result.content step.status success # 写入上下文供后续步骤引用 context[steps][step.id] { status: step.status, output: step.output } except Exception as e: step.status failed step.error str(e)运行示例项目包含一个 CLI 演示程序用于展示完整的规划与执行过程。启动 MCP 服务器 确保 MCP 服务已启动提供基础工具能力。uv run python -m code.MCP.mcp_server运行 Planning CLIuv run python -m code.Planning.demo_planning_cli.py执行效果示例看吧是不是确实很简单最后我们用一个真实案例将这些知识点串起来unsetunset小红书爆款一键发布unsetunset先上一些效果图在Agent基础能力工具调用、记忆、规划逐步完善后我们开始探索更具实用价值的集成场景。社交媒体内容创作与发布是一个典型的重复性工作流程适合通过自动化提升效率。我们今天用Agent来实现从小红书主题输入到平台发布的全流程自动化。该Agent接收自然语言指令如生成一篇关于露营装备的推荐笔记自动完成内容创作、配图生成、平台登录、内容填充及发布的全过程。其整体流程如下unsetunset核心组件内容生成引擎unsetunset我们在Coze平台构建了一个多节点协同的工作流专门生产符合小红书平台特性的结构化内容包。该工作流不是简单的文本生成而是遵循爆款公式的标准化生产线这里有几个核心点一、主题分析与结构规划节点这里也可以不用Coze但是他里面已经有了很多工作流挺好用的。用户输入爆文主题可以是一个新闻稿也可以是引发思考的一句话比如下文中的“Gemini3 是目前最强 AI 吗”随后调用LLM分析主题关键词利用大模型节点中的新闻搜索技能收集到的信息整理后输出文案最终输出内容大纲框架包含标题变体、情绪钩子、分段逻辑、互动结尾设计二、文案生成与图片提示词生成输入内容大纲框架处理根据生成的文案再次调用大模型利用提示词生成图片风格控制短句结构、emoji插入策略、口语化转换、热点词融合输出文生图提示词和图片三、结构化打包节点输入前述节点产出的所有素材处理将标题、正文、标签、图片、封面建议打包为标准化JSON上传飞书方便查看和管理输出格式示例async function main({ params }: Args): PromiseOutput { // 构建输出对象 const ret { fields: [ { fields: { 小红书文案: params.content, 小红书标题: params.title, 小红书图文地址: params.imageUrl }, record_id: params.record_id } ] }; return ret; }实现步骤拆解当我们有一段文字素材、新闻稿甚至只是一句话灵感时如何快速生成适用于抖音、小红书、公众号这三个主流自媒体平台的内容这三个平台用户活跃度高风格各异传统手动改写耗时耗力因此我们希望通过自动化方式实现“一次输入多平台适配”。飞书多维表格在这里承担了“内容数据库”的角色。为了支持后续自动化流程首先要设计清晰的字段结构。先建立一个线索表用于存放初始内容素材如文字素材、新闻稿或简单的一句话灵感再建立文章产出表用于存放扣子写回的文章数据包括图片的URL标题文章现在飞书表格设计好以后根据飞书的表格字段去设计扣子工作流Coze工作流实现在Coze工作流中为大模型节点添加了“新闻识别”技能使其能够根据简短的一句话自动生成完整的文章。当输入内容较少时大模型会自动提取关键词进行新闻搜索获取相关信息作为语料进而辅助文章生成提示词的设计对模型理解任务至关重要推荐使用Markdown格式进行结构化组织明确指定角色、任务、技能、要求和输出格式等。这种结构化的方式能够帮助大模型更准确地把握任务目标提升生成内容的质量。选用的是豆包1.6深度思考模型该模型在内容生成质量上表现更优但运行速度相对较慢。若提示词较为复杂且对生成时长要求不高推荐使用思考模型以获得更优质的结果考虑到公众号、小红书和抖音在内容形式上的显著差异我对不同平台进行了独立设计公众号以文章为主提示词需设计得更加详尽确保内容深度和结构完整。小红书与抖音以图文或短视频为主需将文章内容进一步转化为适合图文生成的提示词。三个平台的内容生成流程执行完毕后结果会自动写回到飞书表格中便于后续管理与使用。注意工作流偶尔可能因思考模型运行超时而报错建议适当延长等待时间或配置错误处理机制此处不展开详述。以下为完整流程示例输入内容为“Gemini3 是目前最强 AI 吗”下面是飞书中收集到的信息现在开始飞书对接扣子扣子工作流制作完成后需要发版发版后的工作流就是一个API可以提供给外部引用调用。飞书对接扣子在飞书平台配置自动化流程时选择飞书字段触发器为按钮。用户可以通过点击按钮发送HTTP请求从而触发已经封装好的扣子工作流实现流程的自动化启动完成触发器配置后在飞书的自动化流程编辑器中进一步设置按钮操作。下图展示了飞书与扣子工作流对接流程unsetunset核心组件浏览器操作工具unsetunset在工作流部分处理结束后在生成内容这块问题不大了但Agent并不具备发布功能所以这里还需要操作浏览器浏览器操作与Computer-Use也是非常基础的Agent工具了。与传统的基于DOM元素定位的自动化工具不同我们采用了一种更接近人类操作方式的方法让LLM理解屏幕内容并做出决策。核心原理是通过计算机视觉分析浏览器界面结合页面HTML结构让LLM像真人一样看到页面并决定下一步操作。核心代码实现如下这里的 Agent其实是 browser-use 工具里封装好的一个内置 Agent。它运行时需要三个核心参数llm、task、browserllm我们传入的大模型用来进行决策与执行。task我们用自然语言编写的指令让 Agent 知道要完成什么任务。browser我们提前初始化好的浏览器工具提供网页访问、检索能力。回顾之前开发的旅游 Agent本质结构和这个内置 Agent 完全一致都是 LLM Tools 的组合。区别在于现在我们在自己的 Agent 内部再去调用一个封装好的 Agent这就形成了一个 多 Agent 协作 的示例。执行流程解析视觉理解与决策Agent接收当前浏览器界面的截图和dom信息LLM分析截图中的可视元素按钮、输入框、菜单等基于任务指令和当前界面状态决定下一步操作输出自然语言指令如点击右上角的发布按钮操作执行与反馈系统将LLM的指令转换为具体的浏览器操作执行操作后获取新的页面状态将结果反馈给LLM进行下一步决策自适应与容错处理页面布局变化时LLM能基于视觉信息重新定位元素遇到意外弹窗或错误提示时LLM能理解并处理网络延迟或加载问题时LLM会决定等待或重试特性DOM操作LLM驱动页面适应性依赖固定选择器易失效基于视觉理解适应性强开发效率需要编写大量定位代码自然语言指令开发简单维护成本页面改版需更新代码对小幅变化自动适应容错能力严格匹配失败即停止能理解上下文尝试替代方案操作逻辑线性脚本执行基于理解的智能决策小结至此这个案例就差不多了使用Browser-Use解决了一些问题只不过实践下来这东西没那么稳定大家做demo可以如果生产环境还是上影刀算了。unsetunset结语unsetunset文章内容很长了这里不赘述了本次课程核心有两个案例第一个几乎将Agent的关键词Function Calling、MCP、Skills用完了的旅游助手第二个是新增的一个自媒体相关工具会用一些奇奇怪怪的工具至于如何将他们串起来大家多多感受即可。总之都是Agent…这里给大家精心整理了一份全面的AI大模型学习资源包括AI大模型全套学习路线图从入门到实战、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等资料免费分享扫码免费领取全部内容1. 成长路线图学习规划要学习一门新的技术作为新手一定要先学习成长路线图方向不对努力白费。这里我们为新手和想要进一步提升的专业人士准备了一份详细的学习成长路线图和规划。可以说是最科学最系统的学习成长路线。2. 大模型经典PDF书籍书籍和学习文档资料是学习大模型过程中必不可少的我们精选了一系列深入探讨大模型技术的书籍和学习文档它们由领域内的顶尖专家撰写内容全面、深入、详尽为你学习大模型提供坚实的理论基础。书籍含电子版PDF3. 大模型视频教程对于很多自学或者没有基础的同学来说书籍这些纯文字类的学习教材会觉得比较晦涩难以理解因此我们提供了丰富的大模型视频教程以动态、形象的方式展示技术概念帮助你更快、更轻松地掌握核心知识。4. 2026行业报告行业分析主要包括对不同行业的现状、趋势、问题、机会等进行系统地调研和评估以了解哪些行业更适合引入大模型的技术和应用以及在哪些方面可以发挥大模型的优势。5. 大模型项目实战学以致用当你的理论知识积累到一定程度就需要通过项目实战在实际操作中检验和巩固你所学到的知识同时为你找工作和职业发展打下坚实的基础。6. 大模型面试题面试不仅是技术的较量更需要充分的准备。在你已经掌握了大模型技术之后就需要开始准备面试我们将提供精心整理的大模型面试题库涵盖当前面试中可能遇到的各种技术问题让你在面试中游刃有余。7. 资料领取全套内容免费抱走学 AI 不用再找第二份不管你是 0 基础想入门 AI 大模型还是有基础想冲刺大厂、了解行业趋势这份资料都能满足你现在只需按照提示操作就能免费领取扫码免费领取全部内容