来源: https://github.com/datawhalechina/agentic-ai/blob/main
反思(Reflection)
- 核心概念:让模型对自己的输出进行检查,评估和改进
- 工作流程:
- 初始生成:模型根据任务要求生成一个初步结果
- 自我评估/外部评估:将该结果作为输入,再次提示同一个另一个模型,要求对结果进行批判性分析(如检查正确性,风格,效率,并给出改进建议)
- 迭代优化:将评估反馈提供给模型,让他基于反馈生成一个更好的版本
- 循环往复:此过程可以迭代多次,直到达到满意的质量
- 关键点
- 这是有效性能提升技术,虽然不能保证100%完美,但是能带来显著的性能提升
- “反思”可以是同一个模型,也可以是引入的“审查者”角色独立生成
- 评估标准可以是客观的(可以是代码能否运行),也可以是主观的(代码风格)
如何通过反思/反馈模型来改进我的结果?
这个过程好像人类的写作“先写完初稿,然后回头阅读发现问题(模糊不清,拼写错误,漏写署名),然后进行修改,最终得到完善的文稿”
案例一: 写邮件
- 生成初稿
- 向LLM发送一个初始提示(Prompt),例如“Write an email…”
- LLM根据提示词生成第一个版本的输出(Email V1)
- 反思和改进
- 将第一版的输出(Email V1)作为新的输入,再次发送给LLM
- 这次提示语不同,例如“请反思这份邮件草稿,并给出改进版”
- LLM基于自身初稿分析,生成最终,质量更好的第二版
案例二:写代码
基础版:模型自省
- 步骤1: 提示 LLM 编写一段代码(code V1)。
- 步骤2: 将 code V1 再次输入给 LLM,提示其“检查代码中的错误并写出改进版”。
- 结果: 得到修复了潜在 bug 的 code V2。
进阶版:利用“思考模型” (Reasoning Models)去“检查代码中的错误并写出改进版”
- 不同的 LLM 有不同的专长。可以使用一个擅长快速生成的模型来写初稿,再用一个“思考模型”(Thinking Model)、更擅长逻辑推理和错误排查的模型来进行反思和改进。
- 这种组合能发挥各自的优势,达到“1+1>2”的效果。
终极版:结合外部反馈来反思
- 步骤1:生成初稿(code v1)
- 步骤2:执行代码,在沙盒环境中运行code v1
- 步骤3:获取外部反馈,系统捕获代码实际输出(Output)或者错误信息(Errors),或者执行上下文(内存/时间)
- 步骤4:反思和改进,将code v1,Output/Errors一起作为输入,交给LLM进行反思,要求根据具体的,客观的反馈来重写代码
- 步骤5:获得最终基于LLM真实执行结果,修正错误的code v2
总结
- 反思并不难使用和理解,这是工程实践,因为不能保证模型每次都100%正确,但能带来“适度的性能提升”,是性价比非常高的优化手段
- 外部反馈非常关键,反思的有效是因为是否利用了外部信息,比如运行代码,查询数据库或者调用API,讲这些结果作为反馈就能让模型进入更深层次的反思,得到更优的结果
- 设计哲学就是如果能获得额外信息,请尽量融入反思流程,这是提升鲁棒性和输出质量的核心策略
为什么不直接一次性生成?
论文《Self-refine: Iterative refinement with self-feedback》的关键图表
- 横轴 (X-axis): 7种不同的任务,包括情感反转、对话响应、代码优化、数学推理等。
- 纵轴 (Y-axis): 性能得分(Performance %)。
- 柱状图配对: 每个任务下有两组柱子:
- 浅色柱子 (Light bar): 代表“零样本提示”(即直接生成)下的性能。
- 深色柱子 (Dark bar): 代表“相同模型+反思过程”下的性能。 在所有7个任务、所有4个被测试的模型(GPT-3.5, ChatGPT, GPT-4, Claude)中,加入反思步骤后的深色柱子,无一例外地高于对应的浅色柱子!
结论:反思模式在各种任务上都能稳定地提升性能。即使是最强大的GPT-4,在加入反思后,其表现也能得到进一步增强。这说明反思是一个普适且有效的优化策略。
如何编写高效的提示词
- 明确指示反思动作
- 补药含糊说“请改进”,而要说“请审查,请检查,请验证”
- 明确告诉模型你要它做什么,比如“审查电子邮件初稿”或“验证HTML代码”
- 制定检查标准
- 要列出具体的评判标准
外部反馈的案例
避免提及竞争对手:模型有时会在文案中不必要地提及竞争对手的名字(如 “Our company’s shoes are better than RivalCo”)。
- 外部反馈工具:编写一个代码工具,使用正则表达式对模型的输出进行模式匹配,自动检测是否包含竞争对手名称。
- 反思流程:
- 模型生成初稿。
- 工具扫描文本,发现“RivalCo”。
- 将“检测到竞争对手名称”的反馈信息传回给模型。
- 模型基于此反馈,重新撰写一份不提及竞争对手的新版本。
事实核查:模型生成的历史内容可能存在不准确之处(如 “The Taj Mahal was built in 1648”)。
- 外部反馈工具:调用网络搜索API,查询关于泰姬陵建造时间的权威资料。
- 反思流程:
- 模型生成初稿。
- 工具发起网络搜索,返回结果:“泰姬陵于1631年下令建造,1648年完工”。
- 将搜索结果作为额外输入,提供给反思模型。
- 模型基于更精确的历史事实,重写文本,使其更准确。
遵守字数限制:模型生成的博客文章或摘要常常超出预设的字数上限。
- 外部反馈工具:开发一个简单的字数统计工具。
- 反思流程:
- 模型生成初稿。
- 工具统计字数,发现“超过字数限制”。
- 将“当前字数”和“字数限制”等信息作为反馈,传回给模型。
- 模型基于此反馈,压缩或精简内容,重新生成符合字数要求的版本。
表格展示了三种常见的挑战及对应的工具化反馈来源:
| Challenge (挑战) | Example (示例) | Source of feedback (反馈来源) |
|---|---|---|
| 提及竞争对手 | “我们公司的鞋子比 RivalCo 好” | 模式匹配(Pattern matching for competitor names)使用正则表达式等工具扫描输出,若发现竞争对手名字,则将其作为批评性输入反馈给模型,要求其重写文本。 |
| 事实核查文章 | “泰姬陵建于1648年” | 网络搜索结果(Web search results)通过网络搜索核实历史事实(如泰姬陵实际于1631年下令建造,1648年完工),并将精确的时间段作为额外输入提供给反思智能体,以生成更准确的版本。 |
| 超出字数限制 | 生成的文章超过指定字数 | 字数统计工具(Word count tool)编写代码精确统计字数,如果超出限制,则将该信息反馈给 LLM,要求其重新尝试,以更准确地达到期望的输出长度。 |
总结:外部反馈的核心价值
- 打破信息孤岛:外部反馈让模型能够接触到其训练数据之外的新鲜、实时、客观的信息。
- 解决模型固有缺陷:对于模型不擅长的任务(如精确计数、事实核查),外部工具可以完美弥补。
- 实现闭环优化:形成“生成 -> 执行/检查 -> 获取反馈 -> 反思改进”的自动化闭环,大幅提升工作效率和输出质量。
- 学习系统化地让模型调用外部工具,是构建强大智能体应用的关键。
工具使用 (Tool Use)
- 核心概念: 赋予语言模型调用外部工具或函数的能力,以扩展其功能边界。
- 工作流程:
- 识别需求: 模型在处理任务时,判断需要调用哪个工具。
- 调用工具: 模型生成调用该工具的指令或参数。
- 执行与返回: 工具执行操作(如搜索网络、计算数学公式),并将结果返回给模型。
- 整合结果: 模型利用工具返回的结果来完成最终任务。
- 工具类型举例:
- 信息收集: Web search, Wikipedia, Database access.
- 分析计算: Code Execution, Wolfram Alpha, Bearly Code Interpreter.
- 生产力: Email, Calendar, Messaging.
- 图像处理: Image generation, Image captioning, OCR.
- 关键点: 工具使用极大地增强了模型的能力,使其不再局限于文本生成,而是能与现实世界互动并解决更广泛的问题。
什么是工具
工具即函数,模型自主决策关键在于,模型拥有自主决策权。它不再是被动地根据内部知识库生成答案,而是能主动判断:在当前情境下,是否需要、以及应该调用哪个工具来完成任务。 就像人类借助锤子、扳手等工具能完成徒手无法做到的事情一样,语言模型通过调用“函数工具”,也能突破自身训练数据和能力的限制,变得无比强大。
简单工具执行流程
例子:工具使用的运作流程 以“现在几点?”为例,清晰展示了工具使用的完整闭环:
- 输入提示 (Input Prompt): 用户提问 “What time is it?”。
- 模型决策 (Model Decision): LLM 意识到自己无法提供实时时间,于是决定调用名为 get_current_time() 的工具。
- 工具执行 (Tool Execution): 系统执行该函数,返回精确的时间值,例如 15:20:45。
- 结果反馈 (Result Feedback): 这个时间值被作为新的上下文(对话历史)回传给 LLM。
- 最终输出 (Final Output): LLM 结合这个新信息,生成自然语言回复:“It’s 3:20pm.”
整个过程的关键点:
- 工具是函数:get_current_time() 是一段 Python 代码,它负责与系统时钟交互并返回字符串。
- 模型自主选择:模型自行决定何时、何地调用哪个工具。
- 动态上下文:工具返回的结果会融入对话历史,供模型后续推理使用。
何时调用,何时不调用?
工具使用的一个重要特性是条件性调用。 模型并非对所有问题都盲目调用工具,而是能智能判断。
- 调用工具的例子:当被问及“现在几点?”,模型知道需要实时数据,因此调用 get_current_time()。
- 不调用工具的例子:当被问及“绿茶含多少咖啡因?”,模型可以基于其内部知识库直接回答:“Green tea typically contains 25-50 mg of caffeine per cup.”,无需调用任何工具。 这体现了模型的“智能”——它能区分哪些信息是静态的(可内化),哪些是动态的(需外求)。
工具使用的实际应用示例
| Prompt (提示) | Tool (工具) | Output (输出) |
|---|---|---|
| “你能找到加州山景城附近的一些意大利餐厅吗?” | web_search(query="restaurants near Mountain View, CA") | “Spaghetti City 是一家位于山景城的意大利餐厅…” |
| “给我看看买了白色太阳镜的顾客。” | query_database(table="sales", product="sunglasses", color="white") | “28位顾客购买了白色太阳镜。他们是…” |
| “如果我存入500美元,年利率5%,10年后我会得到多少钱?” | interest_calc(principal=500, interest_rate=5, years=10) | “$814.45” |
多工具协作
对于更复杂的请求,模型可以串联调用多个工具,形成工作流。 案例:日历助理
- 用户请求: “请在周四我的日历中找一个空闲时段,并与Alice预约。”
- 提供的工具集:
- check_calendar(): 查询日历,返回空闲时段。
- make_appointment(): 创建预约。
- delete_appointment(): 取消预约。
- 模型执行流程:
- 首先调用 check_calendar(),获得结果:“Thursday, 3pm; Thursday, 4pm; Thursday, 6pm”。
- 基于返回的信息,模型决定选择“3pm”这个时段。
- 接着调用 make_appointment(time=“3pm”, with=“Alice”)。
- 工具返回确认信息:“Meeting created successfully!”。
- 最终,模型整合信息,回复用户:“Your appointment is set up with Alice at 3 PM Thursday.”
](https://github.com/datawhalechina/agentic-ai/blob/main/images/3.1.3.png)
总结工具使用是构建下一代 AI 应用的关键技术。它让语言模型从“只会聊天”的伙伴,进化为能够“动手做事”的智能助手。 核心价值:
- 超越知识边界:通过调用工具,模型可以获取实时数据、访问数据库、执行计算。
- 实现复杂逻辑:支持多步推理和工具链协作,处理现实世界的复杂需求。
- 提升应用价值:无论是餐厅推荐、零售分析还是个人日程管理,都能因工具而变得更实用、更强大。
创建工具
LLM本身并不会直接执行代码或调用函数,它被训练的核心能力是生成文本。 如何让LLM学会调用函数的过程,核心思想是模型不直接调用,而是“请求”调用。工具其实就是一些代码/函数。如今的主流语言模型都经过直接训练去使用工具,没有训练就必须得写提示词来告诉模型如何使用工具。
早期方法(手动提示工程):
- 在 LLM 尚未被直接训练来使用工具时,开发者必须通过编写详细的系统提示词来“告诉” LLM 如何请求调用工具。
- 例如,指示 LLM 在需要调用
get_current_time工具时,必须输出特定格式的文本:“FUNCTION: get_current_time()”。 - 这种方法虽然有效,但需要开发者手动处理 LLM 的输出,解析其意图,然后执行相应的函数。
- 现代方法:
- 当前主流的 LLM 都经过了直接训练,能够原生地理解何时以及如何请求调用工具。
- 开发者不再需要像过去那样在提示词中硬编码特定的触发语法(如全大写的 “FUNCTION”),而是只需向 LLM 提供工具的描述和可用性,模型会自行决定何时调用。
实现工具使用:
- 开发者编写工具函数:例如 get_current_time()。
- 开发者编写系统提示词 (System Prompt):告诉模型,如果它想使用某个工具,应该如何格式化它的输出。
- 模型根据提示词输出特定格式的文本:这个文本不是最终答案,而是一个“请求”,例如 FUNCTION: get_current_time()。
- 开发者编写解析代码:读取模型的输出,识别出这个“请求”,然后真正地调用对应的函数。
- 将函数结果回传给模型:把函数返回的结果作为新的上下文输入给模型,让它生成最终的自然语言回复。
就像你不能直接命令一个只会说话的人去帮你买咖啡,但你可以告诉他:“如果你想去买咖啡,请说‘我要买一杯美式’。” 然后你听到这句话后,自己去帮他买。
手动提示工程方法详解
以get_current_time工具为例,展示完整的交互流程:
步骤一:提供工具和系统提示
实现工具:开发者编写好
get_current_time()函数。设计系统提示 (System Prompt):编写一个提示词,明确告知 LLM 它可以访问这个工具,并规定调用它的精确格式。
You have access to a tool called get_current_time. To use it, return the following exactly: FUNCTION: get_current_time()
步骤二:用户提问与模型响应
用户提问:“What time is it?”
LLM 决策:LLM 分析问题后,意识到需要获取当前时间。
LLM 输出:根据系统提示的要求,LLM 不会直接回答,而是输出预设的触发文本:
FUNCTION: get_current_time()
步骤三:开发者代码介入
- 解析输出:开发者编写的程序读取 LLM 的输出。
- 识别意图:检查输出中是否包含 “FUNCTION” 关键字。
- 提取参数:如果包含,则提取出要调用的函数名
get_current_time及其参数(此例中无参数)。 - 执行工具:程序实际调用
get_current_time()函数,获得返回值(如"08:00:00")。
步骤四:反馈结果并生成最终答案
- 构建对话历史:将工具的执行结果(如
"08:00:00")连同之前的对话历史(用户问题、LLM 的函数请求)一起,作为新的上下文输入给 LLM。 - LLM 生成最终回复:LLM 接收到包含工具执行结果的新上下文后,知道之前发生了什么(用户问时间 -> LLM 请求调用函数 -> 函数返回了“8点”),于是生成自然语言的最终回复:“It’s 8am.”
处理带参数的工具
当工具函数需要参数时,流程类似,但提示词和 LLM 的输出需要包含参数信息。
示例:获取指定时区的时间
实现工具:编写一个带参数的函数
get_current_time(timezone)。修改系统提示:
You have access to a tool called get_current_time for a specific timezone. To use it, return the following exactly: FUNCTION: get_current_time("timezone")用户提问:“What time is it in New Zealand?”
LLM 输出:LLM 会根据提示格式,输出带有具体参数的文本:
FUNCTION: get_current_time("Pacific/Auckland")开发者代码:解析出函数名和参数
"Pacific/Auckland",然后调用get_current_time("Pacific/Auckland")。反馈与回复:将执行结果(如
"04:00:00")反馈给 LLM,最终 LLM 回复:“It’s 4am in New Zealand.”
总结:工具使用的核心流程四步循环:
- 提供工具 (Provide the Tool):开发者编写好功能函数。
- 告知模型 (Tell the LLM):通过系统提示词,明确告诉模型有哪些工具可用,以及如何“请求”调用它们(即输出什么格式的文本)。
- 解析并执行 (Parse and Execute):开发者编写代码,监听模型的输出,识别其“请求”,并实际执行对应的函数。
- 反馈结果 (Feed Back Result):将函数执行的结果作为新的上下文,送回给模型,让它继续推理或生成最终答案。 这个流程的关键在于,开发者扮演了“翻译官”和“执行者”的角色,弥合了语言模型的“文本生成”能力与现实世界“函数执行”能力之间的鸿沟。
工具调用语法
工具调用的本质:
LLM(大语言模型)本身不会直接调用工具。
LLM 会“请求”开发者去调用某个工具,开发者负责执行该工具并将其结果返回给 LLM。
在开发社区中,人们常简化说“LLM 调用了工具”,但这在技术上并不准确,仅是一种便捷的说法。
AI Suite 库:
- 这是一个开源库,由 Andrew Ng 及其团队开发。
- 它提供了一种统一、简便的语法来调用多个不同的 LLM 提供商(如 OpenAI)。
- 该库的核心功能之一是自动处理工具描述,极大简化了开发流程。
以 get_current_time 函数为例
工具定义:
fromdatetimeimportdatetimedefget_current_time():"""Returns the current time as a string"""returndatetime.now().strftime("%H:%M:%S")使用 AI Suite 库调用工具的基本代码框架:
importaisuiteasai client=ai.Client()response=client.chat.completions.create(model="openai:gpt-4o",# 指定使用的模型messages=messages,# 传递给 LLM 的消息数组tools=[get_current_time],# 定义 LLM 可以访问的工具列表max_turns=5# 设置工具调用的最大轮次,防止无限循环)解析:
- model: 选择要使用的 LLM,此处为 OpenAI 的 gpt-4o。
- messages: 传递给模型的对话历史或提示信息。
- tools: 这是最核心的部分。只需将你希望模型能访问的函数对象(如 get_current_time)放入一个列表中即可。
- max_turns: 设置一个上限,防止模型在工具调用上陷入无限循环。通常设为5即可,除非你的任务异常复杂。
AI Suite 的优势: 该库的语法与 OpenAI 原生 API 非常相似,但提供了更高的抽象层,使得开发者可以专注于业务逻辑,而非繁琐的 API 细节。它还支持轻松切换多个 LLM 提供商。
AI Suite 如何自动化工具描述
AI Suite 的强大之处在于其自动化能力,它能将你的 Python 函数无缝转换为 LLM 可理解的格式。
当你将 get_current_time 函数传入 tools 参数后,AI Suite 会在后台自动为其生成一个 JSON Schema。这个 Schema 是传递给 LLM 的真实数据结构。
{"type":"function","function":{"name":"get_current_time","description":"Returns the current time as a string","parameters":{}}- 自动生成过程:
- 函数名 (name): 直接提取 Python 函数的名称。
- 函数描述 (description): 自动从函数的 docstring 中提取。
- 参数 (parameters): 对于无参函数,此部分为空对象 {}。
AI Suite 处理带参数的函数
工具定义:
fromdatetimeimportdatetimefromzoneinfoimportZoneInfodefget_current_time(timezone):"""Returns current time for the given time zone"""timezone=ZoneInfo(timezone)returndatetime.now(timezone).strftime("%H:%M:%S")参数解析:
{"type":"function","function":{"name":"get_current_time","description":"Returns current time for the given time zone","parameters":{"timezone":{"type":"string","description":"The IANA time zone string, e.g., 'America/New_York' or 'Pacific/Auckland'."}}}}AI Suite 不仅能提取函数名和描述,还能识别出 timezone 参数,并将其类型(string)和详细说明(来自 docstring)也一并纳入 Schema。这样,当 LLM 决定调用此函数时,它就知道需要提供一个类似 ‘America/New_York’ 的字符串作为参数。
工作流程:
- 开发者定义函数: 编写一个带有清晰 docstring 的 Python 函数。
- AI Suite 自动化封装: 在调用 client.chat.completions.create 时,AI Suite 自动读取函数信息,生成标准的 JSON Schema。
- LLM 接收并决策: LLM 接收到包含所有可用工具描述的 Schema。它会根据当前的对话上下文和用户需求,决定是否需要调用某个工具。
- LLM 发出请求: 如果需要,LLM 会生成一个包含工具名称和所需参数的请求。
- 开发者执行工具: AI Suite 的客户端接收到 LLM 的请求后,会自动调用开发者定义的对应函数,并传入指定的参数。
- 结果返回与迭代: 函数执行的结果会被送回 LLM,LLM 可以基于此新信息继续思考,甚至发起下一次工具调用。整个过程最多可重复 max_turns 次。
- 最终响应: 当所有轮次结束或 LLM 决定不再调用工具时,它会生成最终的文本响应返回给用户。
代码执行工具:
- 终极灵活性: 与其他工具不同,代码执行工具赋予了 LLM 几乎无限的可能性。因为代码本身可以完成任何计算、数据处理或外部交互任务。
- 开发者赋能: 通过提供这个工具,开发者实际上是在告诉 LLM:“你可以让我为你执行任何你认为必要的代码。”这极大地扩展了 LLM 的能力和应用场景。
工具使用 - 代码执行 Tool Use: Code Execution
代码执行(Code execution)是让大型语言模型(LLM)能够编写并运行代码,以解决用户提出的任务。
- 核心优势:
- 强大能力: LLM生成的代码方案常常出人意料地聪明和有效,能解决各种复杂任务。
- 灵活性: 相比于为每个功能手动创建独立工具,让模型自己写代码是一种更灵活、可扩展性更强的方法。例如,一个科学计算器有大量功能按钮,不可能为每个按钮都创建一个工具。
- 提升应用性能: 许多语言模型的训练者会专门优化模型,以确保其在应用中代码执行功能表现良好。
示例:简单计算器
传统方法:预定义工具集
- 场景:构建一个能输入数学文字题并解答的应用。
- 方法:创建一系列预定义工具(如
add,subtract,multiply,divide)。 - 流程:
- 用户输入:“Add 13.2 and 18.9”。
- LLM 识别需求,调用
add工具。 - 工具执行计算,返回结果
32.1。 - LLM 将结果格式化后返回给用户。
- 局限性:
- 面对新需求(如“2的平方根是多少?”),需要不断添加新工具(如
sqrt,exponentiation)。 - 现代科学计算器功能繁多,为每个按钮都创建独立工具不切实际。
- 面对新需求(如“2的平方根是多少?”),需要不断添加新工具(如
替代方案:让模型自己写代码
方法概述
- 核心理念:与其逐个实现功能,不如让系统自己编写并执行代码来解决问题。
- 优势:极大地扩展了模型的能力边界,使其能处理任何可以通过编程解决的问题。
实现步骤
设计系统提示词 (System Prompt):
- 指令模型:“编写代码来解决用户的问题”。
- 要求模型将答案以 Python 代码形式返回,并用
<execute_python>和</execute_python>标签包裹。
模型输出:
对于查询 “What’s the square root of 2?”,模型可能输出:
<execute_python> import math print(math.sqrt(2)) </execute_python>
提取与执行:
- 使用正则表达式等模式匹配技术,从模型输出中提取被标签包裹的代码。
- 在安全的沙盒环境中执行提取出的代码。
- 获取执行结果(例如
1.4142135623730951)。
反馈与格式化:
- 将数值结果传回给 LLM。
- LLM 根据原始问题,生成一个格式良好的最终答案(例如:“The square root of 2 is approximately 1.4142.”)。
执行代码的方式
- Python 的
exec()函数:这是一个内置函数,可以执行传入的任意字符串代码。虽然强大,但也带来了安全风险。 - 专用工具:存在一些专门用于安全执行代码的工具,可以在更安全的沙盒环境中运行。
进阶:带外部反馈的反思
- 概念:当代码执行失败时,将错误信息(如
SyntaxError)反馈给模型。 - 流程:
- 模型生成第一版代码草稿。
- 执行代码,捕获错误。
- 将错误信息连同原始任务一起发送给模型。
- 模型反思错误,生成改进后的第二版代码。
- 效果:通过这种迭代过程,模型有时能修正错误,得到更精确的答案。
安全考量:安全的代码执行
- 核心风险:在沙盒环境外运行由模型生成的任意代码是有风险的。
- 真实案例:
- 一位团队成员使用的高度智能体化代码执行器,曾错误地执行了
rm *.py命令,删除了项目目录中的所有 Python 文件。 - 幸运的是,该成员有备份习惯,未造成实质损失。
- 一位团队成员使用的高度智能体化代码执行器,曾错误地执行了
- 最佳实践:
- 必须使用沙盒环境:这是保护系统、防止数据丢失或敏感数据泄露的最佳做法。
- 轻量级沙盒:推荐使用像 Docker 或 E2B 这样的轻量级沙盒环境,它们能有效隔离代码,降低损坏系统或环境的风险。
- 现实情况:尽管有风险,许多开发者仍会直接执行模型生成的代码而不做过多检查。但为了安全,应坚持使用沙盒。
总结
- 重要性:代码执行是使智能体式应用变得极其强大的关键工具。
- 行业趋势:许多大型语言模型的训练者会专门优化模型,以确保其在应用中代码执行功能的良好表现。
- 未来方向:
- 开发者需要手动为智能体系统创建并添加工具。
- 一个新的标准——MCP (Model Context Protocol)正在兴起,它旨在让开发者更容易地访问一套庞大的工具集,供大型语言模型使用,从而简化开发流程。
工具使用 - MCP Model Context Protocol
定义:MCP(Model Context Protocol,模型上下文协议)是由 Entropy 提出的一个标准,旨在为大型语言模型(LLM)提供一种标准化的方式来访问外部工具和数据源。目的:解决开发者在构建智能体式应用时,需要为每个应用重复编写代码来集成不同工具(如 Slack, GitHub, Google Drive 等)的痛点。现状:该协议已被许多公司和开发者广泛采用,形成了一个活跃的生态系统。
原始问题与解决方案
传统开发模式的问题
重复造轮子:
- 发者 A 构建 App 1,需要集成 Slack、Google Drive、GitHub 和 PostgreSQL。
- 开发者 B 构建 App 2,同样需要集成这些工具。
- 每个应用都必须独立编写封装代码来调用各个工具的 API。
- 如果有
m个应用和n个工具,整个社区的工作量是m × n,效率低下且浪费资源。
MCP 的解决方案
- 引入共享服务器:MCP 提出了一种标准,允许应用程序通过一个共享的 MCP 服务器来访问工具和数据源。
- 工作量优化:
- 不再是每个应用都创建自己的工具封装。
- 只需要开发
n个 MCP 服务器(每个对应一个工具),然后让m个应用去连接这些服务器。 - 整个社区的工作量从
m × n降低到m + n,实现了巨大的效率提升。
MCP 的核心组件
客户端 (Clients)
- 角色:希望访问外部工具或数据的应用程序。
- 示例:Cursor, Claude Desktop, Windsurf。
- 功能:向 MCP 服务器发送请求,获取数据或执行操作。
服务器 (Servers)
- 角色:提供工具和数据源的软件服务。
- 示例:Slack, Google Drive, GitHub, PostgreSQL。
- 功能:作为“包装器”,接收来自客户端的请求,并将其转换为对原始工具 API 的调用,然后将结果返回给客户端。
- 来源:部分服务器由服务提供商开发,但也有大量第三方开发者贡献。
MCP 的能力范围
- 初始设计:侧重于为 LLM 提供更多上下文,最初的工具主要是用于“获取数据”(fetch data)。
- 当前发展:MCP 的能力已扩展,不仅能访问数据,还能调用更通用的功能和执行操作。在 MCP 文档中,这些统称为“资源”(resources)。
实际演示:Claude Desktop 使用 GitHub MCP 服务器
- 场景:用户在 Claude Desktop 中输入查询:“总结该 GitHub 仓库的 README 文件内容”,并附上 URL。
- 流程:
- Claude Desktop 作为 MCP 客户端,识别到这是一个需要访问 GitHub 的请求。
- 它向已连接的 GitHub MCP 服务器发送一个请求,参数包含文件路径 (
README.md)、仓库名 (aisuite) 和所有者 (andrewng)。 - GitHub MCP 服务器执行请求,从仓库下载文件内容。
- 服务器将长文本响应返回给 Claude Desktop。
- Claude Desktop 将接收到的内容反馈给 LLM,LLM 生成一份简洁、格式良好的摘要。
- 第二次查询:用户询问“有哪些最新的 Pull Request?”。
- 同样,客户端向服务器发送“List pull requests”的请求。
- 服务器返回 JSON 格式的拉取请求列表。
- LLM 将其整理成清晰易读的列表,包括标题、状态、作者和描述等信息。
规划 (Planning)
核心概念: 让模型自主决定完成一个复杂任务所需的步骤序列,而不是由开发者硬编码。
工作流程:
- 任务理解: 模型接收一个复杂请求(如“生成一张女孩读书的图片,姿势与示例图中的男孩相同”)。
- 路径规划: 模型自动分解任务,决定需要调用哪些工具以及调用的顺序。
- 例如:先用 openpose 模型提取男孩的姿势 -> 再用 google/vit 模型根据该姿势生成女孩的图片 -> 接着用 vit-gpt2 模型描述图片 -> 最后用 fastspeech 模型将描述转为语音。
- 执行: 按照规划的步骤依次执行。
关键点:
- 这种方式比硬编码的流程更灵活,但控制难度更大,也更具实验性。
- 它允许模型在面对新任务时,自行构思解决方案,有时会产生令人惊喜的结果。
多智能体协作 (Multi-agent collaboration)
- 核心概念: 雇佣多个具有不同专长的角色(智能体)协同工作,共同完成一个复杂项目。
- 工作流程:
- 角色分配: 为不同的智能体分配特定角色(如研究员、市场专员、编辑)。
- 分工合作: 各个智能体根据自己的角色和能力,执行相应的子任务。
- 沟通协调: 智能体之间相互沟通、传递信息,共同推进项目。
多智能体系统在许多复杂任务上优于单智能体系统:
| 任务 | 单智能体 | 多智能体 |
|---|---|---|
| 人物传记撰写 | 66.0% | 73.8% |
| 多模态理解 (MMLU) | 63.9% | 71.1% |
| 国际象棋走子 | 29.3% | 45.2% |
- 关键点:
- 多智能体协作通常能产生比单个智能体更好的结果,尤其在处理复杂任务(如撰写人物传记、下棋)时。
- 研究表明,多智能体系统在多项任务上的表现优于单智能体系统。
- 其缺点是更难控制和调试,因为无法提前预知各个智能体的行为。