Why: 经典文档工程的解决思路
过去在编写文档的一些痛点,诸如于:
- 文档代码不同步。即文档的 API 变化可能落后于代码,导致 API 与文档出现不一致。
- 频繁的 API 变更。API 变更时,文档需要手动进行更新,不能自动化同步。
- 概念不统一。对于同一个概念,文档的不同地方描述不一致。
- 重复的文档块。文档需要重复引用某一部分的文档,不能像代码一样引用。
- 代码无法运行。按照文档的步骤下来编写的代码、复制的代码,是不能运行的。
几年前,为了提供技术框架文档的质量,我研究了市面上主流的文档生成工具、框架文档构建等,也总结了一些文档生成的最佳实践,诸如:
但是,这些工具都无法满足我的需求,所以在过去我也编写了一系列的文档生成工具,诸如:Forming ( https://github.com/inherd/forming )
// doc-code: file("src/lib.rs").line()[2, 5]
// 读取 "src/lib.rs" 文件的第 2 到第 5 行
// doc-section: file("src/lib.rs").section("section1")
// 读取 "src/lib.rs" 文件中的 section1 相关的代码块
但是,这并不是一个完美的解决方案,因为你经常要因为代码的变化而去更新文档。
WHAT: AI 增强技术文档写作体验
AI 增强的技术文档写作体验是一种创新的方法,将先进的人工智能技术与文档编写和管理深度融合。它通过自动化工具和智能分析,简化了文档创建、 更新和维护的流程,显著提高了文档的质量、准确性和一致性。
作为一个实验项目,我们开始使用 Shire 来生成和维护技术文档。以下是几个主要场景示例:
- 代码注释生成:通过分析代码内容,自动生成相应的文档注释,确保文档与代码同步更新,并减少手动维护的需求。
- 自动化内容生成:基于已有的代码注释,自动生成完整的文档内容,包括 API 说明、使用示例等,显著降低了手动编写和更新文档的工作量。
- 代码示例生成:自动读取项目中的测试用例,并将其作为文档中的示例代码展示,帮助读者更好地理解代码的实际应用场景。
- 动态内容检索:根据特定关键词,智能检索文档内容,帮助用户快速定位所需信息,并自动生成相关文档段落。
通过智能自动化的介入,文档编写变得更加高效和轻松,开发者能够专注于核心开发任务,同时确保文档始终与最新的代码和功能保持同步。
HOW: Shire 智能体语言示例
在这里,我们主要会使用 Shire 语言的三个基本能力:
- 借助 IDE 与项目和 LLM 进行交互
- 基于 pattern-action 的变量定义和生成
- 基于 RAG 函数的内容检索
相关的示例,可以直接阅读 Shire 中的代码:https://github.com/phodal/shire
基础能力:生成自定义风格注释
为了更好的让 LLM 理解代码的函数,我们需要先使用 Shire 编写一个生成注释的指令。如下代码所示:
---
name: "生成注释"
interaction: InsertBeforeSelection
actionLocation: ContextMenu
when: $fileName.contains(".kt") && $filePath.contains("src/main/kotlin")
onStreamingEnd: { insertNewline | formatCode }
---
为如下的代码编写注释,使用 KDoc 风格:
```$language
$selection
```
只返回注释
在这里,我们定义了一个专用于生成 Kotlin 代码注释的指令,通过右键菜单触发。当用户在 Kotlin 文件中选择代码后,Shire 会自动为选中的代码生成相应的注释, 并插入到代码之前。
读取与生成:借助 pipeline 函数,自动生成文档文件
随后,我们就可以根据目标文档路径,诸如 docs/shire/shire-builtin-variable.md
编写对应的生成逻辑。诸如于:
---
name: "Context Variable"
description: "Here is a description of the action."
interaction: RunPanel
variables:
"contextVariable": /ContextVariable\.kt/ { cat }
"psiContextVariable": /PsiContextVariable\.kt/ { cat }
onStreamingEnd: { parseCode | saveFile("docs/shire/shire-builtin-variable.md") }
---
根据如下的信息,编写对应的 ContextVariable 相关信息的 markdown 文档。
你所需要包含的 ContextVariable 信息如下:
$contextVariable
...
在这里,我们定义了一个变量 contextVariable
,它的值是读取所有的 ContextVariable.kt
文件的结果。在运行的时候,Shire 会将这个变量的值 编译到 prompt 中,并发送给 LLM,以生成对应的文档。当 LLM 生成的文档返回后,我们会解析出其中的代码块,并保存到指定的文件中。
除此,当代码库中包含有测试用例时,我们就可以配置示例作为代码示例:
---
name: "Hobbit Hole"
description: "Here is a description of the action."
interaction: RunPanel
variables:
"currentCode": /HobbitHole\.kt/ { cat }
"testCode": /ShireCompileTest\.kt/ { cat }
onStreamingEnd: { saveFile("docs/shire/shire-hobbit-hole.md") }
---
根据如下的代码用例、文档,编写对应的 HobbitHole 相关信息的 markdown 文档。
...
当然了,也可以直接读取原来的文档,然后进行更新。
示例:结合 RAG 技术,自动化分析文档
对于更复杂的场景,则可以直接结合 RAG 与 Shire 的 workflow 来实现。如下所示:
---
name: "Semantic Search"
variables:
"code": /.*.kt/ { splitting | embedding }
"input": "博客创建流程"
"lang": "java"
afterStreaming: {
case condition {
default { searching($output) | execute("SummaryQuestion.shire", $output, $input, $lang) }
}
}
---
You are a coding assistant who helps the user answer questions about code in their workspace by providing a list of
relevant keywords they can search for to answer the question.
...
上述代码中,我们定义了一个变量 code
,它的值是对所有的 *.kt
文件进行分割,并进行向量化。而这里的的 input
则是用户输入的问题, 用于搜索相关的文档内容。
在执行时,会将用户的问题发送给 LLM,由其生成关键词,然后在本地进行检索,最后,将结果发送给下一个流程,即 SummaryQuestion.shire
。 在 SummaryQuestion.shire
中,会将检索结果进行总结,然后生成对应的文档。
总结
在这篇文档中,我们分享了使用 Shire 智能体语言来生成和维护技术文档的经验和思考。Shire 是我们在开发中不断探索和改进的一种智能语言工具, 它不仅简化了文档编写的流程,还有效解决了传统文档编写中的诸多痛点。