上一篇文章中,我分享了自己对 AI Agent 的认知转变过程。今天,我想从实战角度深入聊聊构建 AI Agent 的三个核心概念:RAG、工具调用和任务规划。这些可以说是我在过去半年开发 AI Agent 项目中最常用到的能力了。

从一个真实需求说起

还记得去年年底,我接到一个特别有意思的需求:要给公司内部开发一个技术文档助手,要求能回答任何关于公司内部技术文档的问题,并且能够执行一些简单的运维任务。

最开始的想法很简单:把所有文档扔给 GPT,让它回答问题就完了。但实际上手后,很快就发现这根本行不通:

  1. 文档内容太多,完全超出了模型的上下文窗口
  2. 文档经常会更新,每次都要重新训练太麻烦
  3. 很多问题需要实时查询系统状态才能回答
  4. 有些任务需要分步骤执行,不是单次调用能搞定的

正是这个项目,让我深入理解了 RAG、工具调用和任务规划这三个概念的重要性。

RAG:让 AI 拥有"记忆"的能力

RAG(Retrieval-Augmented Generation)说白了就是让 AI 在回答问题前,先去"查资料"。

拿我们的文档助手来说,我是这么实现的:

  1. 首先把所有文档切分成小块,每块大概 500-1000 字
  2. 用 embedding 模型把每个文档块转换成向量
  3. 存入向量数据库(我用的是 Milvus)
  4. 用户提问时:

    • 先用同样的 embedding 模型处理问题
    • 在向量数据库中找最相关的几个文档块
    • 把这些文档块作为上下文,让 GPT 回答问题

效果立竿见影:

用户:如何在测试环境部署新服务?
Assistant:让我查一下相关文档...
根据我们的部署文档,测试环境部署新服务需要以下步骤:

1. 在 Jenkins 测试环境项目中创建新的部署任务
2. 配置 Dockerfile 和部署脚本
3. 设置环境变量(记得使用测试环境的配置文件)
4. 执行部署流程

需要我详细解释某个步骤吗?或者我可以帮你检查一下测试环境的状态。

这样实现有几个好处:

  1. 实时性:文档更新后,只需要更新向量数据库就行
  2. 准确性:回答都是基于实际文档,不会产生幻觉
  3. 灵活性:可以很容易添加新的文档来源

工具调用:赋予 AI "手脚"

光能查文档还不够,很多时候用户需要实时信息或者要执行某些操作。这时候就需要工具调用能力了。

在我们的项目中,我定义了一系列工具函数:

@tool
def check_service_status(service_name: str) -> str:
    """检查指定服务的运行状态"""
    # 实际实现是调用 K8s API
    return k8s_client.get_service_status(service_name)

@tool
def get_latest_logs(service_name: str, lines: int = 100) -> str:
    """获取服务的最新日志"""
    return k8s_client.get_pod_logs(service_name, lines)

@tool
def restart_service(service_name: str) -> str:
    """重启指定服务(需要权限)"""
    return k8s_client.restart_deployment(service_name)

有了这些工具,AI 就能回答更实际的问题了:

用户:user-service 最近有报错吗?
Assistant:让我查一下日志...

我看到 user-service 最近 10 分钟有几条错误日志:
1. 数据库连接超时(3分钟前)
2. 缓存访问失败(7分钟前)

看起来可能是数据库负载过高导致的。要我帮你重启服务吗?

关键是要让 AI 知道:

  1. 有哪些工具可用
  2. 每个工具是做什么的
  3. 什么时候该用哪个工具
  4. 如何处理工具调用的结果

任务规划:让 AI 学会"思考"

最后一个也是最重要的能力:任务规划。有了这个,AI 就能处理需要多个步骤才能完成的复杂任务。

还是拿部署服务来说,一个完整的部署流程可能是这样的:

用户:帮我部署新版本的 user-service

Assistant:好的,我来帮你规划部署步骤:

1. 首先检查当前服务状态
   > 调用 check_service_status("user-service")
   
2. 检查新版本的配置是否正确
   > 查询部署文档
   > 验证配置文件格式
   
3. 执行部署前检查
   > 检查数据库连接
   > 验证依赖服务状态
   
4. 开始部署
   > 执行部署命令
   > 监控部署进度
   
5. 部署后验证
   > 检查服务状态
   > 验证基本功能
   > 检查错误日志

要我开始执行这个计划吗?

实现任务规划的关键点:

  1. 目标分解:把复杂任务拆分成可执行的小步骤
  2. 依赖管理:理清楚步骤之间的依赖关系
  3. 状态跟踪:记录每个步骤的执行状态
  4. 错误处理:遇到问题时能够调整计划

实践心得

经过这半年的实践,我总结了几点心得:

  1. 循序渐进

    • 先实现基础的 RAG 能力
    • 再添加简单的工具调用
    • 最后才考虑复杂的任务规划
  2. 注重实用性

    • 工具函数要简单明确
    • 多加错误处理和重试机制
    • 保留人工干预的接口
  3. 持续优化

    • 收集用户反馈
    • 分析失败案例
    • 不断调整提示词

写在最后

这三个概念看似简单,但要真正用好却不容易。关键是要在实践中不断摸索和优化。

在下一篇文章中,我会详细讲解如何选择合适的技术栈来实现这些能力。如果你也在做类似的尝试,欢迎在评论区分享你的经验。


远洋录
3 声望0 粉丝

🚀 独立开发者 | 技术出海实践者