从0记录我的第一个agent破壳🐣(缓慢更新中)

8 阅读4分钟

写在前面

我本职工作是做通信协议的,业务流程开发时必须严格按照rfc规范,很多细节问题需要比对rfc原文判断表现是否合理。用LLM解决这个问题的过程中,我发现大语言模型经常产生幻觉,引用不存在的“原文”,或所引段落与rfc存在出入(注:与模型能力,联网搜索等均有关,2026年3月市面主流模型表现已经好不少了)。在此时,我了解到RAG的概念,当时就想天呐这简直绝配。于是,我的第一个agent:rfcExpertAgent破壳诞生了。借此记录我的agent学习过程。

v0.1.0 - 实现基本功能

最初的版本思路很简单,我给模型提供了两种工具:

  1. add工具:下载rfc存进向量数据库
  2. search工具:在向量数据库中检索
@mcp.tool()
async def add_rfc(rfc_id: str) -> str:
    """
    Download and index an RFC document into the vector database.
    
    Args:
        rfc_id: The RFC number (e.g., "7540" or "rfc7540").
    """

@mcp.tool()
async def search_rfc_knowledge(query: str) -> str:
    """
    Search the indexed RFC knowledge base for relevant sections.
    
    Args:
        query: The search query or question about a protocol.
    """

核心流程是两层循环,外层循环读用户输入,内层循环llm判断何时调用工具,何时返回结果结束循环。 后面看了learn claude code发现这正是最简单最朴素的实现方式,详细可参考这个视频,思路是一样的Mini Claude Code-V1-模型即代理

v0.1.1 - 遇到的第一个问题

在问了几个问题后,我发现llm响应速度明显变慢了,尤其是不直接在问题中指明rfc id以及问llm没有回答过的协议。为了找到性能开销点,我给agent接入了langSmith,能够看到llm每一步思考过程,发现llm在遇到新问题时总是优先去调用search工具,查到很多无关问题的内容,大量污染上下文。

我朴素的解决方案是:每次search完,由llm判断索引结果与用户问题是否相关,如果不相关则标记为polluted,根据一张local rfc map尝试重新下载更新向量数据库。这样确实一定程度解决的问题,但是又面临两个新的难题:

  1. 性能极其差:一旦遇到“污染”的索引结果,需要花几分钟判断相关性并重走回答流程
  2. local rfc map不是一个好想法,如果map里没有,重试时agent不知道要怎么做

这两个问题很明显通过小修小补难以解决,于是我开启了第一次重构

v0.2.0 - 引入langGraph管理llm思考流程

本次重构的目标是:

  1. 提升响应速度:通过路由层过滤简单问题,减少不必要的 LLM 调用和工具使用。
  2. 优化架构:采用模块化设计,引入路由网关和细分领域 Agent(优先实现 RFC Expert)。
  3. 增强智能:利用 LangGraph 构建状态机,规范 Agent 的思考和执行流程,减少幻觉和错误调用。
  4. 规范工程:遵循开源项目结构,使用 uv 进行依赖管理。
  5. 建立评测:引入自动化测试脚本,基于 quiz.md 进行效果评分。

第一个比较大的变化是路由网关,让llm根据问题类型分给不同的agent回答,算是一个简单的workflow。这样做是一方面为了避免与网络无关的提问也走复杂的工具调用,比如“你好”这样的提问,llm自身即可回答;另一方面,网络领域不只有rfc知识,还包括组网解决方案,网络产品等等细分领域,引入路由网关实现了一定的可扩展性,为接入其他细分领域agent留出空间。

第二个大的变化是通过langGraph状态机管理rfcExpertAgent工作流程,人工约束了agent工作边界,避免agent在向量数据库没有相关信息的情况下重复search的行为。具体流程如下:

  1. Analyze (思考)
    • 分析用户问题,提取关键协议名称或 RFC 编号。
    • 加载技能:读取 src/skills/skill.md 中的技能描述,辅助 Agent 进行决策和工具调用。
    • 判断是否需要查阅 RFC 文档。
  2. CheckLocal (检查本地)
    • 检查所需的 RFC 文档是否已存在于本地向量库。
    • 状态转移
      • 存在 -> 进入 Search (检索)
      • 不存在 -> 进入 Download (下载)
      • 无法确定/不需要 -> 请求用户输入更多相关信息。
  3. Download (下载)
    • 调用工具下载指定 RFC 文档并入库。
    • 状态转移 -> Search (检索)
  4. Search (检索)
    • 在向量库中搜索相关内容。
    • 状态转移 -> Answer (回答)
  5. Answer (回答)
    • 综合检索到的上下文,回答用户问题。

(未完待续,欢迎大家提供好的建议...)