腾讯Agently框架实战:从零构建自主规划与执行的AI智能体

1. 项目概述:当AI学会“自己动手”

最近在AI圈子里,腾讯开源的一个名为“Agently”的通用Agent系统讨论度很高。简单来说,它不是一个具体的应用,而是一个“框架”或者说“脚手架”。它的核心目标,是让开发者能够像搭积木一样,快速构建出能够自主思考、规划和执行任务的AI智能体。

想象一下,你有一个需求:每天自动分析行业新闻,生成一份简报,并发送到你的邮箱。传统的做法,你需要分别调用新闻爬虫、文本摘要模型、邮件发送接口,然后写一个脚本把它们串起来。而Agently的思路是,你只需要用自然语言告诉这个AI智能体:“每天上午9点,帮我收集科技领域的头条新闻,总结成500字以内的简报,发到我的工作邮箱。” 剩下的,比如去哪里找新闻、如何总结、怎么发邮件,这个智能体可以自己去“思考”并调用相应的工具来完成。这就是所谓的“AI自主化”——让AI不仅会回答,更会“做事”。

这个项目之所以引发关注,是因为它直击了当前AI应用开发的一个痛点:大模型能力很强,但让它稳定、可靠地完成一个多步骤的复杂任务,依然有很高的门槛。你需要处理思维链(Chain-of-Thought)、工具调用(Tool Calling)、记忆管理、流程控制等一系列问题。Agently试图通过一套设计良好的抽象层和运行时环境,把这些复杂性封装起来,让开发者更专注于定义“做什么”,而不是“怎么做”。

从技术栈来看,它主要面向Python开发者,深度集成了各类大语言模型(LLM)的API,并提供了丰富的内置“技能”工具和可扩展的架构。无论是想做一个自动化的数据分析助手,还是一个能操作软件的业务流程机器人,都可以基于它来尝试。接下来,我们就深入拆解一下,如何利用这个系统,真正实现一个AI智能体从零到一的搭建。

2. 核心架构与设计哲学拆解

要理解Agently怎么用,首先得明白它是怎么设计的。它的架构清晰地反映了“让AI自主工作”这一目标,我们可以从几个核心概念入手。

2.1 角色(Role)、会话(Session)与工作流(Workflow)

这是Agently里最基础的三个抽象,理解它们就理解了整个系统的运行逻辑。

角色(Role):你可以把它理解为智能体的“人设”或“岗位说明书”。当你创建一个智能体时,首先要定义它的角色。例如,你可以定义一个“数据分析师”角色,它的设定是“你是一名严谨的数据分析师,擅长从数据中发现问题并用清晰的图表呈现”。这个角色定义会被注入到每次与大模型对话的提示词(Prompt)中,从根本上引导AI的思考方式和回答风格。这比每次对话前都写一大段系统提示要优雅和统一得多。

会话(Session):这是智能体与用户进行单次或多次交互的上下文环境。一个Session包含了当前对话的历史消息、角色的定义、已加载的工具(技能)以及记忆状态。你可以把一个Session看作一次具体的“任务执行过程”。例如,用户开启一个Session,说“帮我分析一下上个月的销售数据”,那么整个分析过程,包括中间可能的多轮问答、工具调用,都会发生在这个Session内,并保持上下文的连贯性。

工作流(Workflow):这是实现复杂任务自动化的关键。一个工作流由多个“节点”组成,每个节点可以是一个简单的LLM调用、一个工具调用、一个条件判断或一个循环。Agently提供了可视化编排和代码定义两种方式来构建工作流。比如,一个“市场报告生成”工作流可能包含以下节点:1. 调用搜索工具获取最新资讯;2. 调用摘要模型提炼关键信息;3. 调用数据分析工具处理相关数据;4. 调用文本生成模型,结合前三步的结果撰写报告;5. 调用邮件工具发送报告。工作流引擎负责按顺序或并行执行这些节点,并处理节点之间的数据传递。

这种设计的优势在于,它将智能体的“身份”(Role)、“对话上下文”(Session)和“任务蓝图”(Workflow)解耦了。你可以为同一个角色设计不同的工作流来完成不同任务,也可以在不同的会话中复用同一个工作流。这种灵活性是构建复杂Agent系统的基石。

2.2 技能(Skill)与工具(Tool)生态

AI要自主化,光会“想”不行,还得会“做”。Agently将“做”的能力抽象为“技能”和“工具”。

技能(Skill):这是一个更高层次的抽象,通常对应一个完整的、可复用的任务解决能力。一个技能内部可能封装了一个或多个工具调用,以及一些逻辑判断。例如,“获取天气”可能是一个简单的技能,只调用一个天气API工具;而“安排会议”则是一个复杂技能,它可能需要依次调用“查询日历空闲时间”、“生成会议邀请链接”、“发送邮件”等多个工具,并处理时间冲突等逻辑。Agently框架鼓励开发者将常用的任务模块封装成技能,便于积累和复用。

工具(Tool):这是与外部世界交互的最小单元。一个工具就是一个具体的函数,它可以是:

  • API工具:调用一个外部HTTP接口,如搜索引擎、数据库、邮件服务。
  • 函数工具:执行一段本地代码,如读写文件、运行一个Python计算。
  • 自定义工具:开发者根据业务需要编写的任何功能。

Agently框架提供了丰富的内置工具,也使得添加自定义工具变得非常简单。只需要用装饰器定义好函数,并清晰地描述函数的用途、输入参数和输出,框架就能自动将其“翻译”成大模型能理解和调用的格式。这是实现工具调用的核心技术点。

注意:在定义工具时,描述(Description)至关重要。大模型完全依赖你的文字描述来决定是否以及如何调用这个工具。描述必须清晰、无歧义,并说明输入参数的格式和含义。一个模糊的描述会导致大模型错误调用或拒绝调用。

2.3 记忆(Memory)与状态管理

一个能自主工作的智能体必须有记忆。Agently中的记忆系统分为几个层次:

  1. 会话记忆:存储在Session中,仅保留当前会话的对话历史。这是最短期的记忆,用于维持对话连贯性。
  2. 缓冲记忆:一种固定长度的短期记忆,通常只保留最近几轮对话的关键信息,防止上下文过长导致模型性能下降或API费用激增。
  3. 长期记忆:这通常需要外接向量数据库(如Chroma, Weaviate, Pinecone)来实现。智能体可以将重要的对话摘要、用户偏好、任务结果等编码成向量存入数据库,在需要时通过语义检索召回。这是实现个性化、持续学习智能体的关键。

在实际开发中,你需要根据智能体的用途来配置记忆策略。对于一个客服机器人,会话记忆和缓冲记忆可能就够了;对于一个个人知识库助手,长期记忆就必不可少。Agently框架提供了记忆管理的接口,让开发者可以灵活接入不同的存储后端。

3. 从零到一:搭建你的第一个AI智能体

理论讲得再多,不如动手实践。我们以一个具体的场景为例:构建一个“市场情报收集员”智能体。它的任务是:给定一个公司名称,自动搜索其最新动态、竞品信息,并生成一份简短的洞察报告。

3.1 环境准备与基础配置

首先,你需要一个Python环境(建议3.8以上)和必要的包。Agently可以通过pip安装。

pip install agently

安装完成后,你需要配置最核心的部件:大模型驱动。Agently支持多种后端,如OpenAI API、智谱AI、百度文心等。这里以OpenAI为例(你需要有自己的API Key):

import agently # 创建Agent工厂,并设置默认的LLM驱动 agent_factory = agently.AgentFactory() agent_factory\ .set_default_llm_driver(\ agently.OpenAIDriver(\ api_key="your-openai-api-key",\ model="gpt-4o", # 或 "gpt-3.5-turbo"\ )\ )

接下来,我们创建一个具体的智能体,并为其赋予角色:

# 使用工厂创建一个智能体实例 market_analyst_agent = agent_factory.create_agent() # 为智能体设定角色 market_analyst_agent\ .set_role("一名专注于科技行业的市场情报分析员")\ .set_goal("高效、准确地收集和梳理指定公司的公开市场信息,并提炼出关键洞察。")\ .set_background("你熟悉互联网科技公司的商业模式,擅长从新闻、财报和行业报告中捕捉有价值的信息。")

至此,一个具有“分析师”人设的智能体就创建好了。但它现在还只会聊天,没有“动手”能力。我们需要为它装备工具。

3.2 装备工具:让智能体拥有“手脚”

假设我们有两个工具:一个用于网络搜索(模拟),一个用于生成报告摘要。我们先定义这两个工具:

# 工具1:模拟网络搜索(实际项目中应接入SerperAPI、Google Search API等) @agent_factory.tool_manager.register_tool( name="search_web", desc="根据查询关键词,搜索最新的网络资讯。返回包含标题、摘要和链接的列表。", args_schema={ "query": {"type": "string", "description": "搜索关键词"} } ) def mock_search_web(query: str): # 这里是模拟数据,真实情况应调用API return [ {"title": f"关于{query}的最新融资消息", "summary": "某科技媒体披露...", "url": "https://example.com/1"}, {"title": f"{query}发布新产品", "summary": "该公司于近日推出了...", "url": "https://example.com/2"}, ] # 工具2:生成报告摘要 @agent_factory.tool_manager.register_tool( name="generate_summary", desc="根据提供的原始信息列表,生成一份结构化的中文摘要报告。", args_schema={ "company": {"type": "string", "description": "公司名称"}, "info_list": {"type": "array", "description": "原始信息字典列表"} } ) def generate_summary(company: str, info_list: list): # 在实际中,这里可能会调用另一个LLM来精炼内容 # 此处简化为格式整理 report = f"## {company} 市场动态简报\n\n" for idx, info in enumerate(info_list, 1): report += f"{idx}. **{info['title']}**\n" report += f" {info['summary']}\n" report += f"\n---\n*报告基于模拟数据生成,共分析{len(info_list)}条信息。*" return report

定义好工具后,需要让智能体知道它可以使用这些工具:

# 为智能体加载工具 market_analyst_agent\ .load_tool("search_web")\ .load_tool("generate_summary")

现在,这个智能体已经“知道”自己可以调用search_webgenerate_summary这两个功能了。当它接到任务时,就会自主判断是否需要以及何时调用它们。

3.3 设计并执行工作流

对于“收集情报并生成报告”这个多步骤任务,最适合用工作流来编排。我们用代码定义一个简单的工作流:

# 定义一个工作流函数 async def market_intelligence_workflow(agent, company: str): # 步骤1:指示智能体进行搜索 print(f“开始搜索‘{company}’的相关信息...”) search_instruction = f“请使用搜索工具,查找关于‘{company}’公司最新的市场动态、融资新闻或产品发布信息。” # 让智能体“思考”并执行搜索。这里会触发工具调用。 search_result = await agent\ .input(search_instruction)\ .start() # 从结果中提取工具调用的输出。在实际框架中,可能需要解析消息历史。 # 假设search_result中包含了工具返回的info_list info_list = search_result.get(“info”, []) if not info_list: return “未搜索到相关信息。” # 步骤2:指示智能体生成报告 print(“信息获取完毕,正在生成报告...”) summary_instruction = f“请使用摘要生成工具,基于以上搜索到的信息,为‘{company}’生成一份简洁的报告。” # 这里我们需要将上一步的结果传递给智能体。一种方式是通过会话记忆。 # 更规范的做法是在工作流节点间显式传递数据。此处为演示简化。 # 我们直接调用工具函数(在实际自主化场景中,应由Agent自主决策调用)。 final_report = generate_summary(company, info_list) return final_report # 注意:Agently的工作流引擎可能提供更优雅的DSL或可视化编排。 # 上述代码展示了以编程方式控制流程的思路。

最后,我们运行这个工作流:

import asyncio async def main(): report = await market_intelligence_workflow(market_analyst_agent, “某巴巴”) print(report) # 运行 asyncio.run(main())

这个简单的例子展示了从创建智能体、定义角色、装备工具到编排任务流程的完整链路。虽然这里我们以编程方式“推动”了流程,但在Agently的理想状态下,通过精心设计的提示词和工具描述,智能体在接收到“请帮我分析某巴巴的最新动态”这样的指令后,应能自主地规划出“先搜索,再总结”的步骤并执行。这需要更深入的提示工程和智能体规划能力调优。

4. 深入核心:提示工程与智能体规划

让AI智能体真正“自主”,关键在于其核心“大脑”——大语言模型——如何被引导去思考和规划。Agently框架在这方面提供了一些底层支持,但最终效果很大程度上取决于开发者的提示工程水平。

4.1 结构化提示与推理过程引导

基础的对话式提示往往不足以让模型完成复杂任务。Agently通常采用更结构化的提示模板,将角色、目标、约束、可用工具列表、思考格式要求等整合在一起。例如,一个增强版的提示可能包含:

你是一名市场情报分析员(角色)。 你的目标是:根据用户提供的公司名称,生成一份市场动态简报(目标)。 你必须遵循以下步骤: 1. 使用‘search_web’工具搜索该公司的最新信息。关键词可以包括“公司名 最新动态”、“公司名 融资”、“公司名 产品发布”。 2. 分析搜索结果的标题和摘要,筛选出最近一个月内、最具影响力的3-5条信息。 3. 使用‘generate_summary’工具,将筛选后的信息整理成一份报告,报告需包含概述、关键事件列表和简要评论。 (约束)报告必须用中文撰写,字数在300-500字之间,语气客观专业。 (工具描述)以下是你可以使用的工具: - search_web(query: str): 用于搜索网络信息。 - generate_summary(company: str, info_list: list): 用于生成摘要报告。 (输出格式)请严格按照以下格式输出你的整个思考和执行过程: 思考:[你的推理过程,比如为什么选择这些关键词,如何筛选信息] 行动:调用工具名(参数) // 例如:行动:search_web(某巴巴 最新融资) 观察:[工具返回的结果] ...(重复思考-行动-观察循环)... 最终答案:[生成的完整报告]

这种“思维链(Chain-of-Thought)”加“行动-观察(Act-Observe)”的格式,强制模型进行逐步推理,并明确其工具调用的意图,极大地提高了任务执行的可靠性和可解释性。Agently的运行时环境可以解析这种格式,自动执行“行动”中指定的工具调用,并将“观察”结果反馈给模型进行下一轮思考。

4.2 规划能力与反思机制

对于更复杂的任务,智能体需要具备规划能力。这不仅仅是单步推理,而是能预先构想一个多步骤的计划。Agently框架可以通过以下方式辅助规划:

  1. 任务分解:在提示中要求模型先将复杂任务分解为子任务列表。例如,“要完成一份完整的竞品分析,你认为需要哪些步骤?”模型可能会输出:1. 确定核心竞品;2. 收集各竞品产品信息;3. 收集各竞品市场表现;4. 进行优劣势对比;5. 撰写分析报告。
  2. 计划执行与调整:模型根据分解出的子任务,逐步执行。Agently的工作流引擎可以与此结合,将每个子任务对应到一个工作流节点或一次工具调用。如果在执行某个子任务时失败(如工具返回错误),框架可以触发一个“反思”步骤,让模型分析失败原因并调整计划(例如,更换搜索关键词,或跳过该步骤)。

实现强大的规划能力是Agent系统的前沿,目前大多依赖于GPT-4等高级模型本身的能力。Agently框架的价值在于提供了一个标准化的“沙盒”,让这些规划、执行、反思的循环能够以可控、可观测的方式运行。

4.3 工具描述的优化技巧

工具描述的质量直接决定了大模型是否能用好它。以下是一些优化原则:

  • 具体明确:避免“处理数据”这种模糊描述,应写为“计算输入列表的平均值和标准差”。
  • 说明前置和后置条件:如果工具对输入有特定格式要求(如日期必须是‘YYYY-MM-DD’),或调用后会产生特定副作用(如会向数据库写入记录),应在描述中说明。
  • 示例化:如果可能,在描述中加入一两个调用示例。例如,“例如,调用search_web(‘人工智能 2024趋势’)将返回关于AI趋势的文章列表。”
  • 区分相似工具:如果你有多个搜索工具(如“搜索新闻”、“搜索学术论文”),描述必须清晰区分其数据源和用途。

5. 实战进阶:构建一个可交互的智能体应用

前面我们都是在代码层面操作。如何将它变成一个用户可以交互的应用?Agently框架通常与Web框架结合,打造聊天机器人或自动化任务平台。

5.1 集成FastAPI提供Web API

一个常见的模式是使用FastAPI将智能体封装成RESTful API。

from fastapi import FastAPI, HTTPException from pydantic import BaseModel import asyncio app = FastAPI(title=“市场情报Agent API”) # 定义请求模型 class AnalysisRequest(BaseModel): company_name: str user_id: str | None = None # 可用于区分用户,实现记忆隔离 # 全局初始化智能体工厂和智能体(生产环境需考虑并发和资源池) agent_factory, analyst_agent = init_agent() # 假设的初始化函数 @app.post(“/analyze”) async def analyze_company(request: AnalysisRequest): try: # 为每个请求创建一个新的会话,避免记忆交叉污染 session = analyst_agent.create_session(session_id=request.user_id) # 执行工作流 report = await market_intelligence_workflow(session, request.company_name) return { “success”: True, “company”: request.company_name, “report”: report } except Exception as e: raise HTTPException(status_code=500, detail=f“分析失败: {str(e)}”) # 可以增加其他端点,如聊天接口 @app.post(“/chat”) async def chat_with_analyst(message: str, session_id: str): session = analyst_agent.get_or_create_session(session_id) response = await session.input(message).start() return {“response”: response}

这样,前端应用就可以通过调用/analyze接口来触发智能体的自动化分析任务,或者通过/chat接口进行自由对话。

5.2 实现长期记忆与个性化

要让智能体记住不同用户的偏好,就需要引入长期记忆。我们可以集成一个向量数据库,如Chroma。

import chromadb from agently.contrib.memory import VectorMemoryManager # 初始化Chroma客户端和集合 chroma_client = chromadb.PersistentClient(path=“./chroma_db”) collection = chroma_client.get_or_create_collection(name=“user_memories”) # 创建向量记忆管理器 memory_manager = VectorMemoryManager( embedding_model=“text-embedding-ada-002”, # 需要对应的Embedding模型驱动 vector_store_client=collection ) # 在创建智能体或会话时注入记忆管理器 analyst_agent.set_memory_manager(memory_manager) # 在对话或任务执行的关键节点,让智能体存储记忆 async def store_memory(session, content: str, metadata: dict): memory_id = await session.memory.store(content, metadata) return memory_id # 在需要时,让智能体检索相关记忆 async def retrieve_memory(session, query: str, n_results=3): related_memories = await session.memory.retrieve(query, n_results) return related_memories

例如,当用户说“我不太关心融资新闻,更关注产品迭代”时,你可以将这条偏好作为记忆存储。下次该用户再请求分析时,智能体在规划搜索步骤前,可以先检索“用户偏好”相关的记忆,从而调整其搜索策略,实现个性化服务。

5.3 监控、评估与持续迭代

一个投入使用的智能体系统需要监控。你需要关注:

  • 工具调用成功率:哪些工具经常调用失败?是参数问题还是API不稳定?
  • 任务完成度:用户的任务是否被完整、正确地解决了?可以设计一些自动化测试用例。
  • 成本与延迟:每次任务调用消耗了多少Token?总耗时多少?这对于优化和成本控制至关重要。
  • 用户反馈:提供“结果是否有用”的反馈按钮,收集正负样本,用于微调提示词或优化工作流。

基于这些数据,你可以持续迭代:优化工具描述、调整工作流逻辑、增加新的工具或技能、微调提示词模板。Agently框架的模块化设计使得这种迭代可以相对独立地进行。

6. 避坑指南与最佳实践

在实际开发和部署Agently智能体的过程中,我踩过不少坑,也总结出一些经验。

6.1 常见问题与排查技巧

问题现象可能原因排查与解决思路
智能体不调用工具1. 工具描述不清晰或与任务无关。
2. 提示词未明确要求使用工具。
3. 模型自身“保守”,倾向于用文本回答而非调用工具。
1. 优化工具描述,确保其功能明确、有吸引力。
2. 在系统提示或用户指令中,明确说“请使用我提供的工具”。
3. 在提示中强调“你必须使用工具来完成此任务”,或调整模型温度参数(temperature)尝试。
工具调用参数错误1. 模型误解了参数格式或类型。
2. 参数描述存在歧义。
1. 在工具描述和提示中,用JSON Schema或清晰示例明确参数格式。
2. 使用Agently的args_schema进行严格类型定义,框架会在调用前进行基础校验。
任务执行陷入循环或逻辑混乱1. 任务规划过于复杂,模型“迷路”。
2. 工作流缺少错误处理或终止条件。
1. 将大任务拆解成更小、更原子化的工作流,降低单次规划的复杂度。
2. 在工作流中设置最大重试次数、超时机制和明确的成功/失败状态判断。
上下文长度爆炸,成本激增1. 会话历史未做摘要或清理。
2. 工具返回内容过长。
1. 启用会话记忆的摘要功能,定期将长对话总结成要点。
2. 对工具返回的数据进行预处理,只提取关键信息放入上下文。
智能体“幻觉”,编造工具或结果1. 模型在未获得足够信息时被迫生成答案。
2. 提示词约束力不够。
1. 强化“基于已知事实”的指令,如“仅根据工具返回的信息作答,如果信息不足,请明确说明”。
2. 在输出格式中强制要求引用来源(如“根据搜索工具返回的第X条结果”)。

6.2 性能与成本优化心得

  1. 模型选型:不是所有任务都需要GPT-4。对于工具调用路由、信息提取等结构化任务,GPT-3.5-Turbo可能性价比更高。对于需要深度推理、规划的任务,再使用GPT-4。可以设计一个路由机制,根据任务复杂度动态选择模型。
  2. 提示词精简:反复打磨提示词,去除冗余信息。角色描述、约束条件要精炼。过长的提示词不仅浪费Token,还可能分散模型注意力。
  3. 上下文管理:这是成本控制的核心。积极使用记忆摘要,避免将完整的、冗长的工具响应历史全部塞进下一次对话的上下文。只传递必要的摘要或关键数据。
  4. 异步与并发:如果工作流中有多个可以并行执行的独立步骤(如同时搜索多个关键词),利用asyncio.gather等机制并发执行,可以显著减少总体延迟。
  5. 缓存:对于频繁查询且结果变化不快的工具调用(如查询某个公司的基本信息),可以引入缓存层(如Redis),避免重复调用外部API和消耗LLM Token。

6.3 关于自主化的理性认识

最后,必须清醒认识到,目前的“AI自主化”仍然是在严格框架下的、相对简单的自动化。Agently这样的框架极大地降低了构建智能体的门槛,但它并非魔法。一个真正可靠、能处理复杂边缘情况的智能体,仍然需要:

  • 精细的场景限定:在明确的边界内,智能体可以工作得很好。试图打造一个“万能助理”目前还非常困难。
  • 大量的人工调试:提示词、工具描述、工作流逻辑都需要基于实际测试结果反复调整。
  • 完备的兜底机制:必须有清晰的异常处理流程和人工接管接口。当智能体困惑或失败时,要能平滑地转交给人类处理。

从我个人的实践经验来看,从一个小而具体的场景(比如“自动生成周报草稿”、“自动回复常见客服问题”)开始,逐步扩展其能力边界,是成功率最高的路径。Agently框架为这条路径提供了非常好的工具和基础设施,让开发者可以更专注于业务逻辑和体验优化,而不是重复造轮子。它的开源也意味着社区可以共同贡献更多的技能和工具,加速整个生态的成熟。如果你正想尝试将大模型的能力从“聊天”扩展到“做事”,那么以这个项目作为起点,会是一个相当不错的选择。