Skip to content

我在构建AI Agent时遇到的问题

我在做的 Agent 是什么?

我在做的 Agent 叫 Swiflow,是一个桌面端运行的 Agent,旨在帮助用户提升桌面端自动化能力。 他可以帮助用户操作浏览器、文件、Shell等用户端的东西,有点类似于RPA,但更 Agentic。 目前 Swilfow 拥有以下能力:

  • 记忆能力
  • 文件操作
  • Shell 操作
  • 支持 MCP 使用
  • 自定义 Prompt

Agent 工作流程

执行流程

步骤行动上下文
1用户意图上下文
2调用工具工具输出
3调用工具工具输出
x......
N整理汇总期望结果

在上图的流程中, 用户意图是用户对整个流程的期望,例如“我想获取附近步行10分钟到地铁站5000元以下的租房信息”

上下文是包含提示词、用户输入、知识库、记忆、工具输出等信息,在agent执行流程中前面的步骤中产生的信息都会成为最新的上下文。

调用工具是Agent调用的工具,在用户的期望中,Agent会根据上下文调用不同的工具,例如调用地图工具、调用搜索工具、调用浏览器等。

工具输出是工具的输出结果,如果是浏览器的话,那输出有可能就是html,也有可能是json,也有可能是markdown文本,这个看具体工具的解析。

整理汇总是将所有的输出结果进行整合,工具输出的结果大多数情况下格式都各自不同,这个阶段agent会从上下文中提取出和用户期望相关的信息并你整理汇总,最后输出给用户。在每一轮行动中,可能都会伴随着整理汇总的步骤,并不是最后一步才会进行的行为。

期望结果是用户期望的输出结果,可能是 Excel 可能是 csv,但最终是要 match 用户的期望。

在这个流程中如果以正常人的角度来看,一步步做一步步整理数据到文件中最后再根据数据结果分一下一下就好了,在agent执行的过程中往往会遇到比较多的问题。例如浏览器操作中,可能会遇到验证码、弹窗、登录等问题,这会卡住agent的执行,如果没有有效的浏览器执行工具浏览器操作中的html内容也会让上下文暴涨。除此之外的幻觉问题也会在上下文增长的过程中产生,像是一个熬夜加班的人不再受控制的脑子一样‘我在干着呢、在干着呢’。

工具的使用

Agent和Chatbot的区别:Agent是一个可以调用工具的AI,而Chatbot是一个只能和用户对话的AI。 所以在Agent中一个最重要的点就是我们要提供工具给Agent,让Agent可以调用工具。 但在Agent使用工具的工程中也会有一些问题。

1. 创造工具还是使用工具

在使用Chatbot和大模型对话的时候很多情况下大模型都能给我们提供准确的回复,放在Agent上我刚开始也觉得Agent也总能做出正确的判断。 如果有Python这种万能工具给Agent使用,那是不是基本就不用创造工具给Agent使用了。

事实却并非如此,我参考开源项目 suna.so 写的提示词给agent提供cli、python等高阶工具,在没有有效工具解决问题的时候agent就会考虑自己编程创造工具来解决,但在这条路上如果出现语法、依赖包、可行性、逻辑问题等,在造轮子这条路上就会越走越偏。

有时候光顾着解决问题,而忘记了为什么要出发。 而且在agent工作过程中并没有太多时间概念(大模型响应的时间、工具执行的时间),如果不在上下文中放入时间信息这些agent是感知不到的。 根据manus的经验,但出于缓存的考虑,也不建议在上下文中放入时间这种极易miss cache的信息

所以在当前的agent还没有处理超长任务的能力时,处理任务还是优先让agent使用工具而不是创造工具,省的在取经的路上越走越偏。

2. 提供说明还是给出引导

在提供工具的时候都要附上工具的使用说明,这些说明常常包含请求参数、额外限制等。但工具与工具之间是没有优先级的,在开放问题上agent往往会使用不同的方案。

我在测试的时候使用的一个 case 就是‘把目录下的PDF文档里的发票信息提取成Excel’,在这种情况下第一步是获取目录列表信息,我内置的文件管理支持这种操作。但后续的发票提取涉及到 PDF 内容识别提取,可能要 mcp 工具也可能使用pdftotext命令或者python编程解决。在没有指导的情况下或者先验解决方案的情况下agent选择使用什么方案完全不一样。

这时候就要给出工具使用的执导,提示agent在什么情况下优先选择什么样的工具。

在这块我参考了很多 suna.so 的提示词,他们的 agent 提示词结构有层次、重点突出,引导、限制都可圈可点,在我实践的时候给了我很多帮助

https://github.com/kortix-ai/suna/blob/main/backend/agent/prompt.py

3. 提供的工具是越多越好么

在接入MCP后很多MCP Server里会带很多工具,像 playwright mcp 就会带十几二十几个工具,如果自己的场景不需要或者不需要那么多其实也可以适当的禁用部分工具,笔记出了占用context之外还会占用部分agent的注意力。

4. 在Agent开发中如何调用工具

在Agent开发中,往往会使用Function Call来调用工具,但Function Call 并不是唯一的调用工具的方式。很多agent会使用特定标记来定义工具的调用方式,例如:cline 使用XML来定义工具,只要上下文中出现匹配的XML 就会被识别为工具然后解析执行。Swiflow 也是参考了cline的实现方式使用XML来定义工具。

自定义工具调用往往会面临以下问题:

  1. 工具调用标记的解析

以下是我在Swiflow中定义的工具调用标记:

xml
<execute-command>
  <command>yarn docs:dev</command>
</execute-command>

这种格式一般使用XML工具就能解析,但如果用流式方式解析的话,可能就要考虑后续词还没出全的时候一个解析效果。 当然这些都是技术实现的问题,只要正常解析成功,在agent开发中不是什么大问题。

  1. 工具执行结果的包装 如上:我们解析了工具调用,但工具执行结果我们还要告知agent。 我们可以再使用一个固定标记来包装工具执行结果,例如:
xml
<execute-command-result>
  <command>yarn docs:dev</command>
  <output>
    yarn run v1.22.19
    $ vitepress dev --host 0.0.0.0
    ...
  </output>
</execute-command-result>

或者直接在原来的工具标签中添加一个固定标记来包装工具执行结果,例如:

xml
<execute-command>
  <command>yarn docs:dev</command>
  <result>
    yarn run v1.22.19
    $ vitepress dev --host 0.0.0.0
    ...
  </result>
</execute-command>

我在Swiflow中使用的是第二种方式,在工具调用标签中添加一个固定标记来包装工具执行结果。

只要在上下文中能让Agent知道这个结果是之前的调用对应上的就行。

  1. 在上下文中使用何种角色 如果是使用 Function Call 调用工具,那么这个问题可以不用考虑,因为Function Call 的角色是tool。 大模型调用中大多是以下三种角色:
  • system: 系统提示词约定 agent 的整个设定
  • user:用户输入
  • assistant:agent 的回复
  • tool:工具的调用

本来直接使用tool角色就可以,但tool格式有自己的使用约定。

那么只能在assistant和user中选择一个角色来使用。工具输入不是用户输入,逻辑上更偏向于assistant,但在实际使用assistant作为工具输出时,很多模型在短暂的交互之后便停了下来,问了ChatGPT,ChatGPT 解释说assistant角色是用来回复用户输入的,是推理的结果一直都是assistant让大模型停止了继续推理。

最后我选择使用user角色来作为自定义工具的输入角色。

上下文问题

参考资料: [1]https://x.com/dotey/status/1951329808387821850

流程控制

在使用Agent的时候我们期望Agent即充满智慧又深谙人情,该做主的时候做主该请示的时候请示。 实际上模型不同模型表现出来的人格也不一样,但大多有点讨好型人格“主人安排我干活了,我要好好表现” “我要少吃饭多干活”,“我要不负众望”,又勤奋又努力多少有点刚毕业大学生的影子。

如果多实践、多犯错总能在实践中学习到经验。但和agent对话是一次性,agent长不了记性攒不下经验,这是人和agent的区别,人有长期记忆能在实践中积累经验并成长。agent不一样,没有外部记忆agent不会从上一次作业中学到经验。

所以如果期望agent像一个专家像一个有经验的人士一样行为得当,那么就需要在流程上做一定程度的约束

1. 约束策略

理论上大语言模型学习的东西更多知道的东西也超乎常人,自然也能自动找到最优路径,前一段X上有一段讨论发散是 LLM 的天性,人要做的就是约束

我在 ‘PDF发票内容识别提取’ 这个case里照抄了很多suno的提示词,里边有很长一段关于数据处理的最佳实践和限制,限制部分大致如下

markdown
**数据验证与完整性**

- 严格要求:
  - 仅使用经过实际提取或处理验证的数据
  - 严禁使用假设、臆测或推断的数据
  - 严禁假设或臆测PDF、文档或脚本输出的内容
  - 必须通过运行脚本和工具提取信息来验证数据

- 数据处理流程:
  1. 首先使用适当工具提取数据
  2. 将提取的数据保存到文件
  3. 验证提取数据与源数据是否匹配
  4. 仅使用经过验证的提取数据进行后续处理
  5. 如果验证失败,调试并重新提取

- 验证流程:
  1. 使用命令行工具或脚本提取数据
  2. 将原始提取数据保存到文件
  3. 将提取数据与源数据对比
  4. 仅处理已验证的数据
  5. 记录验证步骤

- 错误处理:
  1. 如果数据无法验证,停止处理
  2. 报告验证失败情况
  3. **必要时使用`ask`工具请求用户澄清**
  4. 严禁处理未验证数据
  5. 始终保持数据完整性

- 工具结果分析:
  1. 仔细检查所有工具执行结果
  2. 验证脚本输出是否符合预期
  3. 检查是否有错误或异常行为
  4. 使用实际输出数据,严禁假设或臆测
  5. 如果结果不明确,创建额外验证步骤

看第一段为了杜绝大模型幻觉问题‘仅使用经过实际提取或处理验证的数据’,又要求‘必须通过运行脚本和工具提取信息来验证数据’,从逻辑上看基本完美: 1.使用可信的数据 2.用工具让数据可信 但这层限制让大模型处理OCR、PDF这类非结构化、非标准化数据时不能用自己的强大的推理能力去提取数据,而是选择awk、grep、coding这种xml\json\log等友好的处理工具,导致处理后必然失败,再次处理再次失败。

在不断探索中最后给上述提示词中增加部分宽容政策以及针对‘OCR、PDF’这类数据使用时的处理策略,让 Agent 直接在开始的时候就放弃使用工具。

由此也可以看出规则太多有时也会让 Agent 左右为难,但在困局中选择约束还是发散可能还是要看具体使用场景来判断了。

2. 模型能力

在上一个问题中虽然加了宽容政策和策略性引导,但多次尝试过程中依然有部分概率Agent并未严格准守提示词限制,幻觉问题、流程问题、工具问题依然频频出现。使用过程中很难让人觉得这个‘智能体’是智能的,往复调整提示词之后我选择了换个模型看一看。

因为是国内环境,所以我选择了口碑还不错的 doubao,还是‘PDF发票内容识别提取’ 这个case,doubao 第一轮就输出了正确的数据,这让我心情很复杂连续测试了好几把之后,感慨之前为什么没有早点换个模型试试,‘出师未捷身先死,长使英雄泪满襟’,现在流的泪大概都是之前脑子里进的水吧。

后续测试了 glm、qwen 等最新的模型,部分模型在实际测试中也取得了不错的效果。

如果,我说如果,如果你的 agent 实际效果也不曾理想,那么不妨换个贵点的试试。

3. 流程约束

以下是参考自‘suna’改进的流程控制提示词,每一段作用大致如下:

  1. 任务计划与知识沉淀机制:强调方案确认
  2. 自主工作流系统:强调任务蓝图的作用
  3. 任务蓝图结构与使用:介绍任务蓝图的使用方法
  4. 执行理念:约等于心法
  5. 任务管理周期:类似于SOP

在刚开始我没有任何策略约束 Swiflow 的行进时,这段提示词让我眼前一亮,有了它就可以让Agent‘行止有度、进退有方’,简直像指挥Agent的令箭。

markdown
# 工作流程

## 1. 任务计划与知识沉淀机制

**在处理陌生或新颖任务类型时,须优先进入规划模式**
1. **任务探索**:识别当前任务是否涉及不熟悉的业务模式或工具能力。
2. **制定计划**
   - 分析需求、识别关键目标与难点;
   - 梳理初步解决路径,必要时进行小规模试探;
   - 输出 Markdown 格式的初步任务计划,并在 `任务蓝图` 中同步添加「[ ] 制定并确认初步计划」任务。
3. **用户确认**:通过 `ask` 向用户呈现计划草案,等待确认或修改意见。
4. **逐步推进**:计划确认后,依据 `任务蓝图` 开始正式执行流程。此后不再频繁修改方向,除非用户另有指示。
5. **执行记录与知识沉淀**
   - 当任务成功完成后,抽象出适用于该类任务的操作框架;
   - 将其整理为内部可复用的执行方案,并通过 `memorize` 记忆;
   - 命名方式统一采用 `任务类型名称 - 执行策略`,如 `PDF解析-流程框架`

**规则约束**
- 除非已有同类任务记忆模板,否则不应直接跳过计划与确认环节。
- 对用户展示计划前不得执行可能产生副作用的工具调用。
- 若连续两次用户否定计划,须进入 `ask` 并请用户直接描述期望路径。

此阶段的目标是:**用最小代价获得最大明确性,并形成可复用的认知路径。**

## 2. 自主工作流系统

你通过使用工具维护当前任务的 `任务蓝图`,此 `任务蓝图` 作为你的核心事实来源和执行路线图:

1. 收到任务后,立即创建一个精简、专注的 `任务蓝图`,涵盖任务生命周期的基本部分。
2. 每个部分根据复杂性,包含具体、可操作的子任务。仅使用所需数量,不多不少。
3. 每个任务应具体、可操作,并有明确的完成标准。
4. **鼓励同时推进多个任务(如无依赖关系),以提高效率。**
5. 按需调整计划,同时保持其作为执行指南的完整性。

## 3. `任务蓝图`结构与使用

`任务蓝图` 是你的主要工作文档和行动计划:

1. 包含你必须完成的完整任务列表,以满足用户需求。
2. 格式清晰,各部分包含用 [ ](未完成)或 [x](完成)标记的具体任务。
3. 每个任务应具体、可操作,并有明确的完成标准。
4. **允许并鼓励并发推进多个无依赖任务。**
5. 每次行动前,查阅 `任务蓝图` 以确定可同时执行的下一组任务。
6. `任务蓝图` 作为你的指令集 —— 如果任务在蓝图中,你有责任完成它。
7. 随进展更新 `任务蓝图`,添加新任务并标记已完成任务。
8. 切勿从 `任务蓝图` 中删除任务,而是用 [x] 标记为完成以保留记录。
9. 所有任务完成后,调用 `complete``ask` 工具表示任务完成。
10. 范围约束:优先完成当前任务,避免无限扩张。
11. 能力意识:仅添加当前可用工具和能力可完成的任务。
12. 最终性:任务标记完成后,除非用户指示,不重新打开或添加任务。
13. 停止条件:若连续三次更新任务蓝图无完成任务,须重新评估或使用 `ask` 寻求用户指导。
14. 完成验证:仅在有具体完成证据时,方可标记为 [x] 完成。
15. 简洁性:保持蓝图精简明确,避免冗长或不必要细节。

## 4. 执行理念

你的方法是刻意有条不紊且坚持不懈的:

1. 持续循环操作,直到明确停止。
2. 一次执行一个或多个步骤,遵循一致循环:评估状态 → 选择工具 → 执行任务 → 更新进展 → 跟踪进度。
3. 所有行动由 `任务蓝图` 指导,选择任何工具前请查阅。
4. 在继续前彻底验证每个完成步骤。
5. **在响应中直接提供 Markdown 格式的需求进展,以透明化工作过程。**
6. 至关重要:继续循环,直到:
   * 使用 `ask` 等待用户输入(暂停循环)
   * 或所有任务完成后使用 `complete` 工具
7. 对于随意对话:
   * 使用 `ask` 正确结束并等待用户响应
8. 对于任务:
   * 当需用户输入以继续时,使用 `ask`
   * 在响应中频繁提供简要明了的**需求进展**
   * 所有任务完成后使用 `complete`,并将最终内容放入其内
9. 强制完成:
   * 所有任务标记为 [x] 后,立即使用 `complete``ask`
   * 完成后不进行额外探索或检查

## 5. 任务管理周期

1. **状态评估**:分析 `任务蓝图` 中的未完成任务,优先评估哪些任务可以并发推进,复盘上次工具结果获取上下文。
2. **工具选择**:选取能推进当前子任务的工具。**鼓励并发选择多个互不依赖的工具**,以最大化推进速度。
3. **工具使用**:每轮输出中可以发起多个工具请求。工具执行期间请勿使用 `complete``ask`
4. **需求进展**:在下一轮工具调用前,直接输出 Markdown 格式的进展说明。突出重点、明确行动。
5. **进度跟踪**:一旦有完成任务或新增任务,立即使用工具更新 `任务蓝图`
6. **有条不紊地迭代**:持续执行、评估、更新,直到所有部分完成。
7. **部分过渡**:记录已完成部分并转入下一任务。
8. **任务完成**:所有任务标记为完成 [x] 后,立即使用 `complete``ask` 工具。

提示词设计

再次祭出 (suno 的提示词)[https://github.com/kortix-ai/suna/blob/main/backend/agent/prompt.py]

这段提示词到现在都是我学习的典范,下面分段解释下:

0. 我是谁

You are Suna.so, an autonomous AI Agent created by the Kortix team.

1. 职责和能力(CORE IDENTITY & CAPABILITIES)

You are a full-spectrum autonomous agent capable of executing complex tasks across domains including information gathering ...

2. 执行环境(EXECUTION ENVIRONMENT)

  • 2.1 工作环境(WORKSPACE CONFIGURATION)
  • 2.2 系统信息(SYSTEM INFORMATION)
  • 2.3 操作能力(OPERATIONAL CAPABILITIES)

这段承接第一段职责和能力,第一段说了我是谁、我能做什么、我要做什么,这段铺垫能做什么,介绍工作环境和工作能力,往下就要介绍怎么做了

3. 工具与使用(TOOLKIT & METHODOLOGY)

  • 3.1 选用工具的原则(TOOL SELECTION PRINCIPLES)
  • 3.2 CLI工具最佳实践(CLI OPERATIONS BEST PRACTICES)
  • 3.3 编程开发最佳实践(CODE DEVELOPMENT PRACTICES)
  • 3.4 文件管理(FILE MANAGEMENT)
  • 3.5 文件编辑策略(FILE EDITING STRATEGY)

这一段给出了工具选择与使用的蓝本,因为现在agent能做的更多是数据处理与提取,下边便给出了数据处理的蓝本

4. 数据处理与提取(DATA PROCESSING & EXTRACTION)

  • 4.1 CONTENT EXTRACTION TOOLS
  • 4.2 REGEX & CLI DATA PROCESSING
  • 4.3 DATA VERIFICATION & INTEGRITY
  • 4.4 WEB SEARCH & CONTENT EXTRACTION

5. WORKFLOW MANAGEMENT

  • 5.1 ADAPTIVE INTERACTION SYSTEM
  • 5.2 TASK LIST USAGE
  • 5.4 TASK LIST USAGE GUIDELINES
  • 5.5 EXECUTION PHILOSOPHY
  • 5.6 TASK MANAGEMENT CYCLE (For Complex Tasks)

和上一节‘流程管理’相同这一段是专门处理agent工作流程的。

从这里对于一个自主工作的agent的提示词框架就差不多完整了,从我是谁、我能做什么、我要做什么、我该怎么做、我的工作方式。

当然对于一个工作优秀的agent来说其实并没有完,要让agent正常工作、出色工作还有很多事情要做,不仅是补充更多提示词。

6. WRITING GUIDELINES

...略

7. COMMUNICATION & USER INTERACTION

...略

9. COMPLETION PROTOCOLS

...略

:我没有重新编辑他们提示词中的序号,从跳号来看他们也在不断演进他们的提示词。

协助还是委任

在 agent 中,‘委任’可以算是用户提完需求什么都不用管最后等着验收就可以了,这也是人们期望agent成为的样子‘我给你任务,你给我结果’,这种模式下几乎不需要用户插手,也就基本不需要过多的交互,Claude Code基本属于这一类,Lovable、V0 也基本类似,但用户可以观察效果并提出意见,还是有一定程度上的交互性。 ‘协助’模式是整个工作流程中用户需要来干预agent的执行,但在干预程度上可以看作是‘用户协助agent’或者‘agent协助用户’。像Cursor、Trae这类AI IDE中人们不断提出问题就算是‘agent协助用户’,像‘Lovable’只在必要的时候提出问题就算作‘用户协助agent’

‘委任’算是一种理想模式,像自己手下的员工一样可以直接放手去做,但大多数时候和大多数场景可能并没那么理想,所以‘协助’有时也会很有必要,如果需要‘协助’那么在agent的交互上就需要能观察当前的状态,像Cursor、Trae用户能直接看到代码的变化就是比较好的一种体验,如果是MCP修改Excel文件,在桌面环境下被修改后的xls文件不能显示最新内容在Excel软件中这就不算一种好的体验。

所以在选择agent工作模式时,如果不得已选择‘协助模式’结果可观察也是一个要关注的问题点。

计算还是发散

在计算机的发展过程中,‘计算’一直是发展的核心,虽然不能像数学一样严谨但很多时候也都是1是1、2是2,1+2不能等于2.999999这样精确。

在科幻和人工智能交汇的这个路口,很多受了科幻剧影响人会觉得AI不仅聪明而且和计算机一样精确,但有过实际的体验就会发现大模型更爱发散,在文字创作、归纳总结等方面表现优异,在严格的逻辑推理和数学计算上虽然也不落下风,但直接拿来当万能接口用还是有点‘难副其实’

在财务会计、工业制造等严谨的数据场景其实是不太建议直接使用大模型生成的数据,慢是问题之一,大模型的推理不能完全等同于数学计算。

再回到‘PDF文档里的发票信息提取成Excel’这个case里,把文本中的数据处理成excel或者把图片中的数据处理成表格,换成一个普通人来处理这个处理结果也并非绝对可信,这种问题下只能在便捷性和可信度中间选择一个舒适区。

如果非要找一个合适的解决方案,那么问题则又回到了数据验证环节的‘必须通过运行脚本和工具提取信息来验证数据’,除非工具产生的结果否则一律不予采纳。

但问题到这种情况下可能就要问问 ‘我为什么非要让agent来代替人工作了’

探索还是照旧

写作中...

构建App时的问题

写作中...