从零到一构建AI学习助手:agent搭建技术实践
写在前面
本系列记录一个agent产品的构建过程。
当我决定开源这个项目时,脑海中闪过的第一个念头是:能不能通过 Build in Public 的方式,让更多人看到一个 AI 产品从概念到落地的完整过程?不是那种“三天速成”的教程,而是真实的踩坑、试错、推翻重来。
这个项目要解决的问题很具体:笔记软件用户“只记不学”的困境,以及K12 中小学教师大量出题的负担。技术方案也很直接:将 Markdown 或 PDF 文件向量化存储,然后通过 AI Agent 以出题、提问等方式帮助用户真正消化知识。
关键决策:架构范式的选择
在开始coding之前,我花了很长时间研究优秀的开源Agent项目。其中一个核心发现改变了整个项目的走向:Tool-Based Delegation(工具即路由)这个设计模式。
传统的Agent架构依赖大量的条件判断——如果用户说了A,就走流程X;如果说了B,就走流程Y。这种方式在复杂场景下会变成难以维护的意大利面条代码。
而Tool-Based架构的核心思想是:让大模型通过阅读函数的文档注释来决定系统走向。你不需要告诉AI“如果用户说‘出题’就调用 examiner”,而是给AI 提供一个名为delegate_to_examiner的工具,在它的docstring里详细描述“什么时候应该用这个工具”。
这个设计哲学把路由逻辑从代码层提升到了语义层,让系统具备了真正的“理解能力”。
第一部分的实践过程
Part1 环境搭建与模型接入
在选择基础模型时,必须明确验证它对核心能力的支持程度。在开发过程中,我选择了DeepSeek API,它的Function Calling能力表现出色,参数提取准确率很高。
Part2 状态管理的精细设计
Agent的状态管理是整个系统的神经中枢。我需要追踪三类关键信息:
-
对话历史(messages)
-
已加载的文档列表(documents_loaded)
-
用户的错题记录(wrong_questions)
关键的是 Reducer 函数的设计。对于wrong_questions这个字典类型的状态,我需要实现“累加而非覆盖”的合并逻辑。参考优秀开源项目的实现,我使用了 {**existing, **new} 这个Python字典解包技巧,简洁地实现了新值覆盖同key旧值的语义。
还有一个细节值得记录:remaining_steps字段。这是LangGraph的create_react_agent内部要求的必需字段,但官方文档里没有明确说明。我是通过运行时报错信息反向推导出来的:
ValueError: Missing required key(s) {'remaining_steps'} in state_schema
part3 工具设计的灵魂——Docstring
我设计了三个delegate工具:
-
delegate_to_ingestor:处理文档上传和解析 -
delegate_to_tutor:回答学习问题和知识讲解 -
delegate_to_examiner:生成测试题目和考试
关键在于:大模型看不到你的Python代码实现,它只能看到函数名、参数类型和docstring。
所以docstring不是写给程序员看的,而是“写给AI看的产品说明书”。在参考优秀开源项目后,我为每个工具编写了详尽的使用说明:
"""Delegate exam generation tasks to the Examiner sub-agent.
Call this tool when the user wants to be tested, quizzed, or wants
practice questions generated.
When to use this tool:
- User asks for a quiz, test, or exam
- User says "给我出题" or "考考我"
- User wants to practice specific topics
When NOT to use this tool:
- User just wants an explanation -> use delegate_to_tutor
- User wants to upload a document -> use delegate_to_ingestor
Args:
topics: List of knowledge topics to cover in the exam
(e.g. ["机器学习", "线性回归", "梯度下降"])
num_questions: Number of questions to generate (default: 5)
difficulty: Difficulty level: "easy", "medium", or "hard"
"""
这种写法的效果立竿见影。在测试中,当用户说“我不太理解什么是反向传播,给我讲讲”时,系统准确地路由到了 delegate_to_tutor;而当用户说“请给我出5道关于线性回归的题”时,系统不仅选对了delegate_to_examiner,还精确提取了topics=[“线性回归”]和num_questions=5这两个参数。
Part4 无边图架构的验证
LangGraph的create_react_agent提供了一个开箱即用的ReAct循环:
-
Agent节点:调用LLM决定是否使用工具
-
Tools节点:执行选中的工具
-
条件边:自动判断是继续循环还是结束
这个设计契合“无条件边”的理念——你不需要手动定义“什么情况下从A节点跳到B节点”,框架会根据LLM的输出自动路由。
但在实现过程中,我遇到了一个环境问题:SSL 证书路径错误。Conda环境激活时自动设置了SSL_CERT_FILE环境变量,指向一个不存在的文件。解决方法很简单粗暴:在所有入口文件顶部加上 os.environ.pop("SSL_CERT_FILE", None)。
最终的端到端测试结果令人满意:
|
|
|
|
|---|---|---|
|
|
|
file_path="/data/ml.pdf" |
|
|
|
topic=“反向传播” |
|
|
|
topics=[“线性回归”]
num_questions=5, difficulty="medium" |
产品思考:技术选型背后的用户价值
以产品经理视角来思考:这些技术决策最终会如何影响用户体验?
Tool-Based 架构的产品价值:用户不需要学习特定的命令格式。他们可以用自然语言表达意图,系统会自动理解并路由到正确的功能模块。这降低了学习成本,提升了交互的自然度。
状态管理的产品价值:通过持久化错题记录,系统可以实现“针对性复习”——下次出题时优先考察用户之前答错的知识点。这是传统笔记软件做不到的。
模型选择的产品价值:DeepSeek 的 Function Calling 准确率直接决定了系统的“理解能力”。如果模型频繁误判用户意图,整个产品体验就会崩塌。
踩过的坑与经验总结
-
类型兼容性问题要在项目初期就明确。Python 版本、依赖库版本的不一致会在意想不到的地方引发问题。
-
Docstring 是 AI 时代的新型 API 文档。它不仅要说明“这个函数做什么”,更要说明“什么时候该用它,什么时候不该用”。
-
测试驱动的开发在 Agent 项目中尤为重要。每个工具、每个状态转换都应该有对应的测试用例,否则很难发现路由逻辑的 bug。
-
选择成熟的开源项目作为参考,但不要盲目照搬。理解设计理念比复制代码更重要。
下一步计划
第一部分只是搭建了主控框架,真正的挑战还在后面:
-
实现文档向量化的 Ingestor 子 Agent
-
设计自适应难度的 Examiner 出题算法
-
构建知识图谱增强的 Tutor 讲解能力
-
优化多轮对话的上下文管理
我会持续以 Build in Public 的方式分享本agent过程,记录下一个产品从0到1的真实轨迹——包括那些弯路、失败和顿悟时刻。
如果你也在构建AI产品,或者对这个领域感兴趣,欢迎关注后续更新。我们可以一起探讨技术方案,分享踩坑经验,见证AI如何真正改变学习方式。
技术栈:LangGraph + LangChain + ChromaDB
适用场景:个人学习笔记消化、K12 教师出题辅助
Build in Public 让我们一起构建项目。
夜雨聆风