Agent 到 AI 同事:OpenBot 背后的任务规划与工具调用原理
← 返回文章列表

Agent 到 AI 同事:OpenBot 背后的任务规划与工具调用原理

从聊天到干活:OpenBot 如何把一句话变成一整套行动

打开任何一个 AI 对话界面,输入“帮我整理下周的客户拜访记录并发送给团队”,你大概率得到的是一段“好的,我建议你这样做……”的建议。但如果你是市场、运营或行政岗位的人,你真正想要的不是建议,而是结果——记录被整理好了,邮件已经发出去了,团队已经收到了。

这就是“聊天机器人”和“AI 同事”之间最本质的差距。前者陪你说话,后者帮你干活。

OpenBot 想做的是后者。它不是又一个能聊天的对话框,而是一个面向非开发者的 AI 助手,核心能力在于两件事:任务规划(Task Planning)和工具调用(Tool Calling)。本文拆解 OpenBot 背后的实现原理,看它如何把用户模糊的意图拆解为可执行的行动计划,并通过调用外部工具完成真实工作。

第一章 从 Agent 到 AI 同事:概念演进

什么是 Agent

配图

Agent(智能体)这个词在 AI 圈已经泛滥了,但多数人并没有说清楚它和“调用一次大模型”有什么区别。最直白的定义是:Agent 是一个具备感知(Perception)、决策(Decision)和行动(Action)能力的闭环系统。

  • 感知:接收用户输入,理解上下文和环境状态
  • 决策:根据目标规划行动步骤,选择合适策略
  • 行动:调用工具、执行操作,并对结果做出反应

单一的模型调用只是“感知 → 生成文字”的线性过程,没有决策和行动环节。而 Agent 是一个循环:它规划、执行、观察结果、再调整,直到完成目标。

从“单轮问答”到“多步骤任务”

配图

传统的对话机器人是“一问一答”模式:你输入,它输出,结束。这种模式适合查资料、翻译文本、写文案,但无法胜任真实工作场景中的多步骤任务。

真实工作是什么样?以“帮我整理下周的客户拜访记录并发送给团队”为例,这个任务包含至少五个步骤:

  1. 找到客户拜访记录的数据源(可能是 Excel 或 CRM 系统)
  2. 读取数据并理解字段含义(客户名、拜访日期、拜访人、结果摘要)
  3. 清洗和格式化数据(补全缺失字段、统一日期格式、剔除无效记录)
  4. 生成一份摘要或报表(按客户汇总、按日期排序、提炼关键信息)
  5. 将结果通过邮件发送给指定团队

每一步都需要不同的能力:文件读取、数据处理、文本生成、邮件操作。一个“问答式”AI 无法完成这些,因为它不能“动手”。Agent 的核心能力恰好是“规划 + 执行 + 反馈”:它把大目标拆成小步骤,逐步执行,并在每一步之后观察结果、决定下一步动作。

AI 同事的定义

“AI 同事”不是营销话术,它有一个很实在的标准:能不能主动完成一项完整的工作任务

如果 AI 能帮你发邮件、整理表格、排日程、生成报表,并且这些操作是真实发生的(不是给你一段“建议代码”让你自己去跑),那它就是“AI 同事”。如果它只能给你“建议”,那它仍然是一个“聊天机器人”。

OpenBot 的定位很清晰:面向非技术用户,把 Agent 的复杂性藏起来,提供一种“同事式”的交互体验。用户不需要理解什么是 API、什么是工具调用、什么是任务分解,只需要用自然语言描述目标,OpenBot 负责拆解和执行。

第二章 任务规划:把大目标拆成小步骤

规划的本质

任务规划是 Agent 的“大脑”。它的核心问题只有一个:如何将用户模糊的自然语言指令转化为一组可执行的子任务序列?

举个例子,用户说:“帮我统计本月加班时长并生成周报邮件。”

这句话信息密度很低,但隐含了大量需要明确的内容:

  • “加班时长”的数据源在哪里?(考勤系统?Excel 表格?)
  • “本月”是指自然月还是最近 30 天?
  • “统计”是按人统计还是按部门统计?要不要计算加班费?
  • “周报邮件”发给谁?格式是什么?

规划的第一件事不是“拆步骤”,而是“搞清楚意图”。

关键机制一:意图识别与目标解析

意图识别在传统 NLP 时代是一个分类问题:预定义几个意图类别,然后做文本分类。但在 LLM 时代,意图识别变成了“结构化信息抽取”——从自然语言中提取出动作、对象、时间、目标等要素。

以“帮我整理下周的客户拜访记录并发送给团队”为例,OpenBot 内部的意图解析模块会生成类似这样的 JSON 结构:

{
  "intent": "send_report",
  "target_entity": "客户拜访记录",
  "time_range": {
    "start": "2025-03-03",
    "end": "2025-03-09"
  },
  "action": "整理并发送",
  "recipient": "team",
  "channel": "email",
  "format": "summary"
}

这个结构化表示是后续任务分解的基础。它让系统知道:要做什么(发送报告)、对象是什么(客户拜访记录)、时间范围(下周)、收件人(团队)。

这个环节最关键的工程挑战是:如何保证 LLM 输出的 JSON 结构稳定。实践中的做法是使用函数调用(Function Calling)机制,让模型严格按照预定义的 schema 输出,而不是自由发挥。OpenBot 会定义这样的工具调用协议:

{
  "name": "parse_intent",
  "parameters": {
    "type": "object",
    "properties": {
      "intent": { "type": "string" },
      "target_entity": { "type": "string" },
      "time_range": { "type": "object" },
      "action": { "type": "string" }
    },
    "required": ["intent", "target_entity", "action"]
  }
}

关键机制二:任务分解(Task Decomposition)

目标解析完成后,下一步是任务分解。这一步依赖 LLM 的推理能力,但不能完全依赖 LLM 自由发挥——需要约束输出格式。

OpenBot 的做法是让 LLM 生成一个结构化的任务列表,每个任务包含:任务描述、依赖的输入、预期输出、调用的工具类型。以上面的“客户拜访记录”任务为例,分解结果如下:

{
  "tasks": [
    {
      "task_id": 1,
      "description": "查找并读取客户拜访记录数据源",
      "input": "data_source=crm_export.csv",
      "output": "raw_records",
      "tool": "file_reader",
      "dependencies": []
    },
    {
      "task_id": 2,
      "description": "清洗数据,统一日期格式并剔除无效记录",
      "input": "raw_records",
      "output": "cleaned_records",
      "tool": "data_processor",
      "dependencies": [1]
    },
    {
      "task_id": 3,
      "description": "按客户汇总生成拜访摘要",
      "input": "cleaned_records",
      "output": "summary",
      "tool": "llm_text_generator",
      "dependencies": [2]
    },
    {
      "task_id": 4,
      "description": "发送邮件给团队",
      "input": "summary",
      "output": "email_sent",
      "tool": "email_sender",
      "dependencies": [3]
    }
  ]
}

这个 JSON 结构的价值在于:它是机器可读的,执行引擎可以直接遍历这个任务列表,按顺序或按依赖关系执行。同时它又是人类可读的,用户可以在执行前检查 OpenBot 的计划是否合理。

关键机制三:依赖关系与执行顺序

任务分解产生的不只是一个列表,而是一个有依赖关系的有向无环图(DAG)。某些任务可以并行执行,某些必须串行。

举一个并行执行的例子:用户说“帮我统计上周的销售数据和客户反馈,生成一份周报”。这里“统计销售数据”和“整理客户反馈”是两个独立的数据源,可以并行处理;但“生成周报”必须等两者都完成后才能开始。

OpenBot 在执行引擎中维护一个任务队列,基于依赖关系决定哪些任务可以立即执行,哪些需要等待:

任务 1: 读取销售数据(无依赖,立即执行)
任务 2: 读取客户反馈(无依赖,立即执行)
任务 3: 生成周报(依赖任务 1 和 2,等待)

失败处理与回退

真实环境中,任务执行不可能一帆风顺。数据文件不存在、字段格式与预期不符、邮件服务返回 500 错误——这些都会发生。OpenBot 的规划器必须处理这些异常。

OpenBot 采用了两层策略:

  1. 预检查:在执行任务前,先检查前置条件是否满足。比如文件是否存在、权限是否足够。
  2. 重试与回退:如果某一步失败,先重试(最多三次);重试仍失败,则尝试替代方案(比如用另一个工具实现同样的功能);如果替代方案也没有,就停下来,向用户报告失败原因,而不是“假装成功”。

这个环节很容易被忽略,但恰恰是“AI 同事”和“玩具 Demo”的分水岭。

规划结果的结构化表示

最终,规划器的输出不是一段自然语言描述,而是一个结构化的任务描述(JSON 或 DSL),供执行引擎读取。这个表示必须包含足够的信息让执行引擎“无需思考就能执行”。

在工程实现上,OpenBot 用 JSON Schema 做校验,确保 LLM 生成的规划结果符合预定义格式,避免“模型自由发挥导致执行引擎崩溃”的经典问题。

第三章 工具调用:让 Agent 真正“动手”

工具的本质

规划只解决了“做什么”的问题,工具调用解决“怎么做”的问题。

工具的本质非常朴素:把外部 API、脚本、软件操作封装为一个统一接口,让 LLM 能够“选择”并“调用”它。

从工程师视角看,工具就是一个函数,有输入、有输出、有副作用(副作用指:发邮件、改文件、创建日历事件等真实世界的影响)。

常见工具类型

在 OpenBot 面向白领用户的设计中,最常见的工具类型包括:

  • 文件读写:读取 CSV、Excel、TXT;写入结果文件
  • 表格处理:对表格数据进行筛选、排序、聚合、透视
  • 邮件发送:发邮件、带附件、支持多收件人
  • 日历操作:创建日程、查询空闲时间、发送会议邀请
  • 网页搜索:抓取网页内容、搜索公开信息
  • 数据库查询:连接内部数据库执行 SQL 查询

工具注册与描述

每个工具在 OpenBot 中注册时,需要附带两样东西:功能描述参数 Schema。LLM 根据功能描述决定“该用哪个工具”,根据参数 Schema 决定“怎么填参数”。

以下是一个邮件发送工具的函数签名示例:

def send_email(
    to: str,          # 收件人邮箱,支持逗号分隔多个
    subject: str,     # 邮件主题
    body: str,        # 邮件正文,支持纯文本
    attachments: list[str] = [],  # 附件路径列表
    cc: str = "",     # 抄送
) -> dict:
    """
    发送一封邮件。成功返回 {"status": "success", "message_id": "xxx"},
    失败返回 {"status": "error", "error": "详细错误信息"}。
    """
    # 实现略

LLM 在规划执行时,会把用户指令映射到这个函数的参数上。例如用户说“把摘要发给团队”,LLM 会填充 to 参数为团队邮件列表,subject 为“客户拜访记录摘要”,body 为生成的摘要内容。

工具描述必须非常精确。如果描述模糊,LLM 可能选错工具或填错参数。OpenBot 在实践中发现,工具描述写得越具体、示例越丰富,LLM 选对工具的概率越高

调用流程

工具调用的标准流程如下:

  1. 规划器生成任务列表,每个任务指定了工具类型和输入参数(参数可以来自用户原始指令,也可以来自前一个任务的输出)
  2. 执行引擎按依赖关系顺序执行,依次调用对应工具
  3. 工具返回结果(结构化数据或状态信息)
  4. 执行引擎将结果传给下一个任务,或者返回给用户
  5. LLM 在关键节点参与:比如生成摘要、提炼关键信息、决定下一步动作

多轮工具调用与中间结果传递

一个复杂任务往往需要连续调用多个工具,中间结果需要在任务之间传递。例如“从 CSV 中提取转化率并做图表,放进 PPT”这个任务,实际调用序列是:

工具 1: file_reader   → 读取 CSV 数据
工具 2: data_processor → 计算转化率(按周分组,计算转化百分比)
工具 3: chart_generator → 生成折线图或柱状图(输出为 PNG 文件)
工具 4: ppt_editor    → 新建 PPT,插入图表,保存文件

中间结果的传递方式是内存中的变量传递,类似 Unix 管道:前一个工具的输出是后一个工具的输入。OpenBot 内部维护一个“共享状态池”,每个任务的输出按任务 ID 存储,后续任务通过引用任务 ID 来获取数据。

这也带来了一个工程难点:数据格式的兼容性。文件读取工具输出的是 DataFrame 格式,而图表生成工具期望输入的是二维数组。OpenBot 在每个工具之间增加了一个“格式转换层”,确保数据能正确流转。

第四章 从开发者到普通白领:OpenBot 的交互设计

隐藏复杂性

OpenBot 的核心用户不是开发者,而是市场、运营、行政、销售这些“普通白领”。这意味着交互设计的第一原则是:用户不需要知道“工具”和“API”的存在

用户不会说“调用一个 email_sender 工具”,他们会说“帮我发个邮件”。OpenBot 需要做的是把后一句话自动翻译成前一句话,执行完成后,再翻译回用户能理解的语言。

这听起来简单,实际做到位非常难。用户说“帮我统计本月加班时长”,系统需要:

  1. 搞清楚“加班时长”数据在哪里(可能根本没有现成的数据结构)
  2. 搞清楚“本月”是自然月还是最近 30 天
  3. 搞清楚统计口径(含不含周末?含不含法定节假日?)
  4. 搞清楚输出格式(表格?图表?邮件正文?)

OpenBot 的策略是:能自动推断就自动推断,不能自动推断就问。在规划阶段,如果某个关键参数缺失且无法从上下文推测,OpenBot 会向用户提出澄清问题,而不是“猜一个值”然后出错。

确认与反馈机制

AI 同事和聊天机器人的另一个区别是:AI 同事需要“责任意识”。它执行的操作有真实世界的影响——发出去了收不回来的邮件、删掉了无法恢复的文件。因此,OpenBot 在关键操作之前,会向用户展示执行计划并请求确认。

交互流程如下:

用户: 帮我整理下周的客户拜访记录并发送给团队

OpenBot: 我计划执行以下操作:
1. 读取 CRM 导出文件(customer_visits.xlsx)
2. 筛选下周(3月3日-3月9日)的拜访记录
3. 按客户生成摘要
4. 发送邮件给团队(team@company.com)
5. 邮件主题:客户拜访记录摘要(3月3日-3月9日)

确认执行?[确认 / 修改]

这个确认机制不是“多此一举”,而是建立信任的关键。用户只有看到 AI 的计划是合理的,才会放心让它执行。OpenBot 的确认页还会展示“预计影响”:发了几封邮件、改了几个文件、创建了几个日程事件。

进度可视化与错误处理

执行过程中,OpenBot 会实时展示当前进度:

✓ 读取客户拜访记录(耗时 0.8s)
✓ 筛选下周拜访记录(找到 23 条)
✓ 生成客户拜访摘要(耗时 2.1s)
→ 正在发送邮件...

如果某一步失败,OpenBot 不会抛出一个“系统错误,请重试”的冷冰冰的提示,而是用人类可读的语言解释问题,并给出建议:

✗ 邮件发送失败
原因:无法连接邮件服务器(smtp.office365.com)
建议:请检查网络连接,或联系 IT 部门确认邮件服务是否正常。
你可以选择:重试 / 跳过此步骤 / 修改收件人后重试

示例场景一:行政人员统计加班时长

行政人员张姐的使用场景:“帮我统计本月加班时长并生成周报邮件。”

OpenBot 的规划输出如下:

{
  "intent": "overtime_statistics",
  "tasks": [
    {
      "task_id": 1,
      "tool": "file_reader",
      "description": "读取考勤数据文件",
      "params": { "path": "attendance/2025-02.xlsx" },
      "dependencies": []
    },
    {
      "task_id": 2,
      "tool": "data_processor",
      "description": "筛选本月加班记录并计算每人加班时长",
      "params": { "filter": "date >= 2025-02-01 AND date <= 2025-02-28", "group_by": "employee_name", "agg": "sum(hours)" },
      "dependencies": [1]
    },
    {
      "task_id": 3,
      "tool": "llm_text_generator",
      "description": "生成周报邮件正文",
      "params": { "prompt": "基于以下加班统计数据,生成一份周报邮件正文:{task_2_output}" },
      "dependencies": [2]
    },
    {
      "task_id": 4,
      "tool": "email_sender",
      "description": "发送邮件给部门负责人",
      "params": { "to": "manager@company.com", "subject": "2025年2月加班统计周报" },
      "dependencies": [3]
    }
  ]
}

张姐不需要理解 JSON,不需要知道什么是“依赖关系”。她看到的只是确认页面上的四行计划,点一下“确认”,几分钟后邮件就发出去了。整个过程她只做了两个动作:输入指令、点击确认。

示例场景二:运营人员制作转化率图表 PPT

运营人员小王的需求更复杂:“从这份 CSV 中提取上周的转化率,做成图表,放到 PPT 里。”

这个任务涉及多工具协作和数据格式转换:

工具 1: file_reader → 读取 conversion_data.csv
工具 2: data_processor → 按日期分组计算转化率(转化数/曝光数)
工具 3: chart_generator → 生成折线图(输出:conversion_trend.png)
工具 4: ppt_editor → 新建 PPT,将图表插入到第 1 页
工具 5: file_saver → 保存为 conversion_report.pptx

技术难点在于数据格式的传递:data_processor 输出的 DataFrame 需要转换为 chart_generator 能接受的二维数组格式;chart_generator 生成的 PNG 文件路径需要传给 ppt_editor

OpenBot 的格式转换层在这里发挥了作用。对于开发者来说,这个环节可能是最复杂的部分,但对小王来说,他只需要说一句话,然后在确认页面看到“我将生成一个包含转化率趋势图表的 PPT”,点击确认即可。

第五章 局限与未来:从“能用”到“好用”

当前挑战:任务规划的准确率

尽管 LLM 的推理能力已经很强,但在复杂模糊指令下的任务规划准确率仍然有限。用户说“帮我弄一下这个”,系统很难判断“弄”是什么意思。用户说“跟上次一样”,系统需要记忆上次的操作上下文。

OpenBot 目前的策略是“多轮澄清 + 学习用户偏好”。如果某个用户经常使用相似指令,系统会记住他的偏好(比如“发给团队”默认指“team@company.com”),下次直接使用默认值。

工具调用的稳定性

工具调用最大的痛点是外部依赖的不可靠性。邮件服务可能宕机、文件可能被锁、API 可能限流、权限可能过期。OpenBot 的应对策略包括:

  • 超时控制:每个工具调用设定超时时间(默认 10 秒),超时后自动重试或报告失败
  • 参数校验:调用前用 JSON Schema 校验参数合法性,避免传空值或错误类型
  • 降级方案:主工具失败时尝试替代工具(比如 A 邮件服务失败,尝试 B 邮件服务)

安全与隐私

普通用户的数据往往更敏感——考勤数据、客户信息、财务报表。OpenBot 必须考虑:

  • 数据权限:每个用户只能访问自己有权限的数据源和工具
  • 操作审计:所有工具调用记录日志,便于追溯
  • 敏感操作确认:删除、覆盖、群发邮件等操作必须二次确认

未来方向

OpenBot 的路线图上有几个值得关注的方向:

  1. 自我学习:记录用户偏好和操作习惯,逐步减少需要用户确认的步骤
  2. 多 Agent 协作:不同工具由不同 Agent 负责(比如“数据 Agent”“邮件 Agent”“PPT Agent”),主 Agent 负责任务调度
  3. 跨平台集成:从内部工具扩展到飞书、钉钉、企业微信等办公平台,让 AI 同事真正融入工作流

总结

OpenBot 的本质不复杂:把“任务规划 + 工具调用”封装成一个对非技术用户友好的产品。它的核心价值在于,让 AI 从“回答者”变成了“执行者”——不再只是告诉你“应该怎么做”,而是直接帮你做完。

对普通白领来说,这意味着自动化的门槛被大幅降低。过去只有会写 Python 脚本的人才能自动化自己的工作流,现在只需要用自然语言描述目标,AI 同事就能接管那些重复、琐碎、多步骤的工作。

对开发者来说,OpenBot 提供了一个值得借鉴的产品化思路:Agent 技术能否落地,关键不在于模型的推理能力有多强,而在于规划是否可靠、工具生态是否丰富、交互设计是否让用户信任。模型再聪明,如果规划结果不稳定、工具调用总出错、用户不放心让它执行,那它就只能停留在 Demo 阶段。

最后想说一点:AI 同事的出现,不是为了取代人,而是把那些重复劳动接过去,让人把精力花在真正需要判断力和创造力的决策上。这也许是“AI 同事”这个概念的真正意义。

上一篇从 Copilot 到 AI 同事:Agent 落地的三个关键转变