精选案例 · Agent / 实践案例
我与 AI 辅助编程的故事
这个案例围绕「我与 AI 辅助编程的故事」记录了一条真实 AI 实践线索,正文重点集中在「缘起」「第一个教训:别让 AI "写一个完整的流水线"」,适合先按任务意图阅读再判断复用。
案例速读
README 标题「我与 AI 辅助编程的故事」下已经出现运行/配置路径、脚本或接口线索、结果证据,正文重点集中在「缘起」「第一个教训:别让 AI "写一个完整的流水线"」,比纯概念介绍更适合进入精选阅读流。 这篇案例的阅读价值在于,它把真实任务、模型辅助过程和可迁移做法放在同一个上下文里,读者可以从 「我与 AI 辅助编程的故事」、「缘起」、「第一个教训:别让 AI "写一个完整的流水线"」、「CLI 设计:从混乱到有序」 进入正文。
- 建议重点看 可参考其中的运行与配置路径、包含可迁移的命令、脚本或接口线索、已有结果或观测证据可用于判断复用价值。结合 Agent / 实践案例 和「任务驱动用户、AI 实践者」这一受众定位,它更适合作为任务检索后的精读材料,而不是只看一句短摘要后快速跳过。
- 正文目录和原始材料仍然是判断依据;导读只帮助你更快定位阅读重点。
- 看点
- 我与 AI 辅助编程的故事
- 读者
- 任务驱动用户、AI 实践者
- 复用
- 可参考其中的运行与配置路径
- 结构
- 12 个目录入口
原文内容
我与 AI 辅助编程的故事
缘起
这个学期我接手了一个课程知识图谱处理流水线的项目。目标很明确:将原始课程材料中的知识点清洗成结构化的多层知识图谱——包含课程、模块组、模块、知识点四个层次,通过 LLM 标注语义属性(认知功能 tag、难度、关键词、学习目标)和关系(前置依赖、组成关系、对比关系等),最终输出可复用的 JSONL 图谱文件。
说实话,刚开始我心里是没底的。项目的代码规模不算小——涉及数据加载、LLM 编排、缓存管理、批量断点续跑、质量审计、节点编辑、关系提取等多个模块。而且要求代码文件控制在 300 行以内,保持可读性和可维护性。我决定把 AI 作为主要的开发伙伴,试试看一个人能不能扛下来。
第一个教训:别让 AI “写一个完整的流水线”
刚开始用 AI 编程时,我犯了一个非常典型的错误——提出过于笼统的需求。
“帮我写一个完整的知识图谱构建流水线”——这个 prompt 下去,AI 确实给了我一大段代码:一个巨大的 Python 文件,里面塞满了数据解析、LLM 调用、关系生成等所有功能。但仔细一看,问题很多:错误处理几乎没有,没有区分课程配置和核心逻辑(导致后续每加一门新课就要改核心代码),文件之间的职责边界模糊不清。
这个教训让我意识到,AI 编程的核心在于 对话式开发。就像你不会让一个人类工程师一次写完整个系统一样,你也不应该这样要求 AI。正确的做法是:把大问题拆解成小问题,与 AI 逐步讨论设计决策、迭代实现、审查质量。
于是我开始重新思考项目的架构。我和 AI 一起梳理了流水线的各个阶段:
原始数据 → 模块规划 → Topic 标注 → 组装清洗 → 生成节点 → 质量审计 → 节点编辑 → 关系提取 → 终审输出
每个阶段一个独立的子命令,对应一个 CLI 入口。我让 AI 先帮我设计好 argparse 的命令层级和各个子命令的参数接口,然后逐个实现。这一次,AI 生成的代码质量明显提高了——因为每个子命令的职责范围已经收窄,LLM 的注意力可以集中在更具体的问题上。
CLI 设计:从混乱到有序
命令行界面是流水线的入口,也是我最早和 AI 合作完成的部分之一。我把我想要的命令结构告诉了 AI:
uv run python -m kg_algograph.cli clean-outputs --course-config ...
uv run python -m kg_algograph.cli plan-minors --course-config ...
uv run python -m kg_algograph.cli annotate-minors --from-line N --to-line M --only-missing
uv run python -m kg_algograph.cli assemble-cleaned --course-config ...
uv run python -m kg_algograph.cli build-graph --course-config ...
uv run python -m kg_algograph.cli node-edit-plan --from-module N --to-module M --concurrency 2
AI 帮我设计了每个子命令的参数,包括 --use-api(是否调用 LLM API)、--only-missing(仅处理未完成的任务)、--from-line/--to-line(支持按行号分批处理)等。这些设计后来被证明非常实用——在 API 调用断断续续的网络环境下,分批重跑的能力省去了我大量的调试时间。
在实现过程中,我还学到了一个重要教训:给 AI 的 prompt 中,硬性约束要明确说明。比如"所有 Python 文件不得超过 300 行"这个约束,如果我不说,AI 倾向于在一个文件里塞很多功能。而明确说了之后,AI 会主动考虑如何拆分文件、抽象公共逻辑。
语义关系标注:从规则到 LLM
关系提取模块是项目中最有挑战性的一部分。这个模块需要识别知识点之间的语义关系——前置依赖、组成关系、实例关系、对比关系、重叠关系等——并输出结构化的 JSONL 格式。
最初我尝试用规则来实现:关键词匹配、Jaccard 相似度、PPT 页码差。很快问题就暴露了:规则能告诉我两个知识点之间"是否存在某种联系",但它无法判断"这是什么联系"。共享 3 个关键词的两个概念,可能是前置依赖、可能是对比关系、也可能只是碰巧提到相同术语。这种语义判断,规则做不到。
我把这个问题和 AI 讨论后,AI 建议转向 LLM 方案:用规则做初步候选召回,然后用 LLM 来做语义分类。AI 帮助我设计了完整的关系类型体系——分三层递进标注,每层的约束条件不同:
关系的三层递进标注
第一层:结构关系。Course → ModuleGroup → Module → Topic 的层级包含关系,由规则自动生成,不经过 LLM。这层处理的是纯粹的组织结构,不需要语义判断。
第二层:同模块内 Topic 关系。LLM 在同一模块内标注 Topic 之间的语义关系。这一层允许 part_of(组成关系,如 Max-Heapify 是堆排序的子算法)、example_of(实例关系)、contrasts_with(对比关系)等。
第三层:跨模块 Topic 关系。跨模块的 Topic 之间标注关系,约束更严格——禁止 part_of 和 prerequisite_of,只保留 example_of、contrasts_with、overlap_with、related_to。
每一层的 prompt 都不同,AI 帮我逐层编写和调试。这个过程中最让我惊讶的是,当我对第三层提出"跨模块的 Topic 之间不应该有 part_of 关系"这个约束时,AI 立刻理解了原因(跨模块意味着知识边界跨越,组成关系应该在同一个模块内表达),然后自动检查了所有层级的 prompt 模板并批量更新了相关约束——不是机械替换,而是理解了修改背后的逻辑。
关系类型体系的演化
关系类型不是一次性设计完成的。最初我们只有 3 种类型:prerequisite_of、example_of、related_to。但经过质量审计发现,related_to 占比超过 50%,语义信息量很低——它只表示"有关联",没有说明是什么关联。
我和 AI 反复讨论后,迭代到了最终版本:7 种语义关系 + 2 个质量控制标记。新增的类型包括 part_of(概念组成)、contrasts_with(对比辨析)、overlap_with(交叉重叠),以及 _trash(垃圾桶)和 _review(待人工审核)。每种关系都有明确的定义、层级约束、方向规则和正反例子。
AI 还帮我设计了关系选择决策树,给定两个 Topic,按决策树逐层判断:
B 中 A 是子步骤/组件?→ part_of
必须先学 A 才能学 B?→ prerequisite_of (分 hard/soft/conceptual)
A 是 B 的实例且更具体?→ example_of
A 和 B 是解决同类问题的并列方法?→ contrasts_with
共享显著内容?→ overlap_with
以上都不是但有关联?→ related_to
这个决策树的优先级逻辑和 AI 反复推敲了好几轮。比如 part_of 隐含了 prerequisite_of(部分在整体之前学),所以两者并存时只需要标记 part_of;contrasts_with 已隐含内容重叠,不需要重复标记 overlap_with。
质量审计:AI 教我如何批判 AI
项目中有一个质量审计模块,负责检查生成的节点和关系是否符合质量标准。这是我第一次真正体会到"用 AI 审查 AI 的输出"这个概念。
节点质量问题
在分析第一轮生成的节点时,我和 AI 发现了一个严重的问题:流水线对每个模块强制规划 8 个知识点(Topic),LLM 为了"凑数",做出了很多奇怪的事情:
- 同一概念被拆成多个节点:"Max-Heapify 算法"和"维护堆的性质"实际上是完全相同的内容,但被拆成了两个节点
- 非知识点混入:“作业与实验”、“背包问题实例数据”、“集合覆盖问题实例”——这些只是课程行政信息或样例数据,根本不是算法知识点
- 粒度过细:“字符串匹配的符号约定”——仅定义了 T/n/P/m 四个符号,应该合并到父概念中
AI 在质量分析报告中清晰地指出了这些问题,并给出了根因分析:minor_planner 阶段的 prompt 中要求"每模块恰好 8 个 Topic",LLM 在数量约束下会拆分概念、凑数造假。解决方案是去掉固定数量,改为范围(4-10 个),让 LLM 根据实际内容密度决定。
节点编辑计划
基于质量分析结果,AI 帮我生成了详细的节点编辑计划——这是人类审校和 AI 协作的典范。计划包含 54 条编辑操作:37 条修改(改名、改 tag、改描述)、14 条合并、3 条删除。
每一步编辑都有明确的理由和置信度,AI 甚至对自身提出的编辑进行了可行性评估:ID 有效性检查(所有引用的 ID 均存在)、操作冲突检查(无链式合并、无同时编辑和合并)、合并方向评估(保留信息量更大的节点)。
这个过程中最让我印象深刻的是,AI 对自己生成的计划也能保持批判态度。它在评估报告中指出了一些自己遗漏的问题:“ALG_16_06 符号约定节点应删除但 plan 漏了”、“ALG_08 模块中 4 个重复节点只处理了 1 对”、“部分 merge 的目标选择可商榷”。这种自我批判的态度,让我对"相信但验证"有了更深的体会。
关系质量分析
关系质量分析同样发现了很多问题。除了之前提到的 related_to 占比过高外,还有:
- 28/146 的 Topic 节点(19%)没有任何语义关系,处于孤立状态
- ALG_02 模块最严重——8 个 Topic 中有 5 个孤立,渐近记号(O/Ω/Θ)之间存在天然的对比和前置关系但全部缺失
- 跨模块关系中存在明显错误:某些 Topic 被标记了同模块内已经存在的关系,实际上应该扩展现有关系而非新建关系
AI 针对这些问题提出了具体的改进方案:提高 LLM 审核覆盖率(当前仅 11/180 条关系经过二次审核)、对孤立节点集中的模块补充关系标注、增加跨模块关系的冲突检测。
缓存与断点续跑:工程化的细节
这是一个容易被忽视但实际开发中非常关键的部分。LLM API 调用在网络不稳定的环境下经常失败,而且标注成本不低。AI 帮我设计了缓存策略:
- 缓存键使用
id + content_hash + prompt_version三重匹配,确保计划内容变化后不会误用旧缓存 - 支持
--from-line/--to-line按行号分批处理,网络中断时只重跑失败的范围 - 使用
--only-missing跳过已缓存的结果,只处理新内容 - 标注结果追加写入,不重写已有缓存
这些设计让我在后续的开发中省了很多事。每次 API 调用失败,不需要从头开始——只需要重新运行同样的命令,AI 会自动跳过已缓存的、只处理失败的。
知识图谱的认知功能分类
还有一个让我觉得很有趣的设计——Topic 节点的 tag 字段。AI 帮我设计了一套认知功能分类体系,将每个知识点标注为五种认知类型之一:
| tag | 含义 | 判断标准 |
|---|---|---|
| 定义型 | 回答"X 是什么" | 形式化定义、符号约定或概念边界 |
| 操作型 | 回答"怎么做 X" | 步骤、流程、伪代码或实现要点 |
| 推演型 | 回答"为什么 X 成立" | 证明、推导、复杂度分析或性质解释 |
| 结构型 | 回答"X 之间怎么组织" | 层级、拓扑、分类或数据结构布局 |
| 应用型 | 回答"X 用在哪里/怎么用" | 具体场景、案例、代码示例 |
这套分类看似简单,但实际标注时经常遇到边界模糊的情况。AI 帮我定义了优先级规则来处理冲突——推演型优先于定义型,应用型优先于操作型等。更重要的是,AI 明确强调:语义属性不得由规则程序补造。如果 API 或人工没有给出字段,程序只能省略,不得用默认值、父节点名称或关键词规则填充。这个原则保证了图谱中每个语义字段都有真实的标注依据。
使用心得的反思
回顾这个项目,最让我受益的不是 AI 写的代码本身,而是和 AI 协作的方式。
1. 硬性约束写在 prompt 里比事后修复更高效
“跨模块 Topic 禁用 part_of 关系”、“所有 Python 文件保持 300 行以内”、“Tapic 属性不得由规则程序补造”——这些约束如果在需求阶段就写在 prompt 里,AI 第一次生成的代码就能满足大部分要求。反之,如果写代码时不提,等 AI 生成了再来修复,往往要改很多处。
2. 让 AI 自我批判
质量审计模块是我在一个 bug 后加上去的。当时 AI 生成的节点编辑计划漏掉了一些明显的问题(比如"符号约定"节点应该删除但没删除),我指出后 AI 不仅修正了这次的问题,还主动建议"以后应该在每次生成计划后运行一次可行性评估",然后真的帮我写了一个评估脚本——自动检查 ID 有效性、操作冲突、合并方向等。
从此我养成了一个习惯:每次 AI 完成一个任务后,让 AI 自己审查一下自己的输出。AI 通常能发现自己的遗漏,然后自动修正。
3. 迭代式设计,不追求一次性完美
关系类型体系从初版的 3 种类型经过多次迭代演变为 7 种类型 + 2 个质量控制标记。每次迭代都是基于真实数据的质量分析反馈。AI 在这个过程中表现得像一个敏捷开发者:先出一个最小可行版本,收集反馈,再迭代优化。这种模式比试图在设计阶段就做完美要高效得多。
4. AI 是讨论伙伴,不是代码生成器
这个项目中最有价值的时刻,往往不是 AI 帮我写代码的时候,而是我和 AI 讨论设计决策的时候。当我在考虑"Topic 层是否应该允许 prerequisite_of 关系"时,AI 帮我分析了利弊:Topic 粒度太细,前置关系容易退化为"有帮助"或"先后讲授",最终结论是收到 Module 和 ModuleGroup 层。当我在考虑"跨模块 Topic 之间应该允许什么关系"时,AI 提出"禁掉 part_of,因为跨模块表达组成关系会模糊知识边界"——这个观点我以前没想到,但它确实说服了我。
最终成果
经过这个学期的开发和迭代,整个流水线从原始数据到干净知识图谱的端到端流程已经跑通。最终输出的图谱包含了:
- 1 门课程、5 个模块组、19 个模块、127 个知识点
- 356 条关系(151 条结构级 + 205 条语义级),覆盖 contains、prerequisite_of、part_of、example_of、contrasts_with、overlap_with、related_to 七种类型
- 所有语义属性来自 API 标注或人工审校,没有规则补造的虚假语义
- 通过了最终审计:Topic 层 prerequisite_of 为 0、跨模块 part_of 为 0、弱 related_to 为 0、重复边为 0
展望
AI 辅助编程正在改变我们的学习方式和开发效率。这个项目的经历让我深刻体会到:善用 AI 工具能让一个人完成过去需要一个团队才能做的事情。更重要的是,AI 不仅帮我写代码,它还在和我讨论架构设计、分析数据质量、提出改进方案——它扮演的是合作者的角色,而不只是代码生成器。
期待在未来的学习中,能够借助 AI 做出更有趣、更有价值的东西!
August @ USTC