接口文档滞后几乎是所有开发团队的通病:代码改了三版,文档还停留在第一版;新同事入职,对着一份过时的文档调试半天才发现参数早已变更。与其反复催促大家手动维护文档,不如换一种思路——让一个Agent来干这件事。它监听代码变更,解析接口定义,调用大模型补全描述性文字,最后输出一份与代码实时同步的文档。本文就以一个具体的案例,完整讲清楚这类API文档生成Agent的设计与实现。

一、Agent的整体架构设计
一个能落地的API文档生成Agent,核心不是简单地“把代码丢给大模型”,而是一套流水线式的处理流程。整个系统可以拆成四个模块:代码扫描器、信息抽取器、描述生成器和文档渲染器。代码扫描器负责找出仓库中所有定义接口的文件,比如Express的路由文件、Spring的Controller或者FastAPI的入口模块;信息抽取器从这些文件中提取结构化数据,包括路径、方法、参数、返回值类型;描述生成器把结构化数据交给大模型,生成人类可读的功能说明和参数解释;文档渲染器则负责把最终结果输出成Markdown或OpenAPI规范格式。
之所以要拆成独立模块而不是全部塞给大模型,有两个原因。第一是上下文长度限制,一个中型项目的代码量轻松超过几十万字符,直接投喂必然丢失细节;第二是准确性,大模型解析代码容易产生幻觉,比如把参数类型猜错,而用确定性的AST解析工具提取结构信息,再让大模型只负责它擅长的自然语言描述部分,准确率会高出一个量级。这种“确定性解析+大模型补全”的混合架构,是当前代码类Agent的主流做法。
另外还需要一个调度层,决定Agent何时触发。常见做法是在Git的post-commit钩子或CI流水线中调用Agent,只在接口相关文件发生变化时才重新生成对应章节,避免全量重跑带来的token浪费。
二、代码解析与信息抽取的实现
信息抽取是整个Agent的地基。以Node.js项目为例,可以借助TypeScript编译器提供的API对源码做AST级别的分析。相比正则匹配,AST方式能准确区分字符串里的"/users"和真正的路由声明,不会被注释或变量名干扰。下面是一个简化版的抽取器实现,它扫描Express路由注册调用,提取方法和路径:
const ts = require("typescript");
const fs = require("fs");
// 解析单个文件并提取路由信息
function extractRoutes(filePath) {
const source = ts.createSourceFile(
filePath,
fs.readFileSync(filePath, "utf-8"),
ts.ScriptTarget.ES2020,
true
);
const routes = [];
// 递归遍历语法树,查找 router.get("/path", handler) 形式的调用
function visit(node) {
if (ts.isCallExpression(node)) {
const caller = node.expression;
if (ts.isPropertyAccessExpression(caller)) {
const method = caller.name.text; // get/post/put/delete
const path = node.arguments[0] && ts.isStringLiteral(node.arguments[0])
? node.arguments[0].text
: null;
if (["get", "post", "put", "delete", "patch"].includes(method) && path) {
routes.push({ method: method.toUpperCase(), path, file: filePath });
}
}
}
ts.forEachChild(node, visit);
}
visit(source);
return routes;
}这段代码的逻辑很直接:先把源文件编译成语法树,然后深度优先遍历,遇到函数调用表达式时检查调用者是否是router对象的属性访问,且属性名是HTTP动词、第一个参数是字符串字面量。命中就记录一条路由。实际项目中还需要处理app.use挂载的前缀、中间件链、装饰器语法等情况,思路一样,只是遍历规则更多。
对于参数和返回值类型,如果有TypeScript类型标注或JSDoc注释,可以继续从AST中读取函数签名的类型节点,还原成文本形式。如果项目完全无类型标注,就只能依赖大模型推断,这时要在文档中明确标注“类型为推断值”,提醒读者核实。信息抽取的最终产出是一份JSON格式的中间表示,后续所有模块都围绕这份JSON工作,这样新增对其他框架的支持时,只需替换抽取器,下游逻辑完全不用动。
三、大模型描述生成与结果校验
拿到结构化JSON之后,就该大模型出场了。它的任务不是解析代码,而是为每个接口生成三段内容:功能概述、参数说明表、错误场景列表。提示词的设计直接影响输出质量,实践中有几个要点值得注意。首先,要把抽取到的结构化数据完整放入提示词,并明确告诉模型“以下信息已确认准确,不要更改”;其次,要求模型只输出JSON,字段名固定,方便程序解析;最后,给出Few-shot示例,让模型学会用简洁的工程师语言而非营销腔来写描述。
const prompt = `你是一个API文档撰写助手。根据以下已确认的路由信息生成文档描述。
规则:
1. 只输出JSON,字段为 summary, params, errors
2. 不要修改给定的路径和参数名
3. 语言为中文,风格简洁准确
路由信息:
${JSON.stringify(route, null, 2)}
示例输出:
{"summary":"根据用户ID查询单个用户的基本信息",
"params":[{"name":"id","desc":"用户唯一标识","type":"string"}],
"errors":[{"code":404,"desc":"用户不存在"}]}`;大模型的输出不能直接采信,必须过一道校验。最基本的是结构校验:用JSON Schema验证返回的字段是否齐全、类型是否正确。更进一步可以做一致性校验,比如检查模型生成的参数列表是否与抽取器得到的参数集完全一致,多出来的参数直接剔除,缺失的参数用默认占位文本补上。这一步看似繁琐,却是Agent可靠性的关键——文档工具一旦输出过几次明显错误的内容,开发者就会彻底失去对它的信任。
还有一个小技巧值得采用:为每段模型生成的内容计算哈希值并缓存。当代码变更只影响部分接口时,未变动的接口直接读缓存,既省成本又保证文档中未变更部分的稳定性,不会因为模型的随机性导致每次生成的措辞都不同。 temperature参数建议设为0.2以下,进一步压低输出的随机性。
四、完整流程串联与输出
最后把各模块串成完整的Agent主流程。输入是项目根目录,输出是一份Markdown文档。主函数按顺序执行扫描、抽取、生成、渲染四步,并输出处理摘要:
const { execSync } = require("child_process");
const path = require("path");
async function generateDocs(projectDir) {
// 1. 扫描所有可能的路由文件
const files = execSync(`git ls-files "*.js" "*.ts"`, { cwd: projectDir })
.toString().split("\n").filter(Boolean);
// 2. 逐文件抽取路由
let allRoutes = [];
for (const f of files) {
if (/router|controller|routes/i.test(f)) {
allRoutes = allRoutes.concat(extractRoutes(path.join(projectDir, f)));
}
}
console.log(`共发现 ${allRoutes.length} 个接口`);
// 3. 为每个路由生成描述(带缓存)
const documented = [];
for (const route of allRoutes) {
const cached = cache.get(hash(route));
documented.push(cached || await llmGenerate(route));
}
// 4. 渲染为Markdown
const md = renderMarkdown(documented);
fs.writeFileSync(path.join(projectDir, "API.md"), md);
console.log("文档已写入 API.md");
}渲染环节没有太多技术含量,但细节决定体验。按路由路径的首段分组,比如所有/user开头的接口归到“用户模块”,目录层级立刻清晰;每个接口附带源文件位置和行号链接,方便读者跳转核对;文档头部加一个生成时间戳和接口总数统计,让读者对文档的新鲜度有判断依据。如果团队使用Swagger生态,还可以把中间JSON转换为OpenAPI 3.0格式,直接导入Apifox或Postman使用。
五、落地时的常见问题与改进方向
真实项目里跑起来后,通常会遇到几类问题。一是动态路由,路径由变量拼接而成,AST静态分析拿不到最终值,这时需要维护一份路由注册表,或在测试环境运行时通过拦截器记录真实请求路径来补全。二是接口数量庞大时的成本控制,除了前面提到的缓存策略,还可以对描述生成做批量合并,一次请求处理多个接口,减少请求次数。三是文档更新通知,可以在Agent完成后向协作工具推送变更摘要,列出本次新增、修改、删除的接口,形成闭环。
更进一步,可以把这个Agent从“批量生成”升级为“增量维护”:为每个接口的文档段落记录代码指纹,只在指纹变化时重新生成对应段落,并支持人工编辑的段落加保护标记,机器不覆盖人工内容。这样人机协作的边界清晰,文档质量会随时间持续提升而不是反复震荡。整体来看,API文档生成Agent的价值不在于替代人写文档,而在于把没人愿意做的初稿工作自动化,让人只需要审核和润色,这个定位恰恰是当前大模型 Agent 最擅长也最容易被团队接受的落地场景。