ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ZLLM:基于大模型的ABAP开发文档自动生成实践

ZLLM:基于大模型的ABAP开发文档自动生成实践 1. 这个项目的源头ABAP 文档为什么总是“欠账”1.1 传统文档方案的三个死穴做 ABAP 开发这些年我见过太多次这样的场景功能上线三个月后业务方要求变更新接手的顾问打开程序对着几千行代码无从下手只能一层层往上翻翻到最顶上发现注释还是三个人之前留下的半句话。文档缺失从来不是能力问题而是流程问题。代码在传输请求里不断迭代文档却留在了最初的版本这是手工文档最无解的死穴。市面上不是没有自动生成文档的工具但大多数停留在“导出方法签名”“列出 FORM 名称”“生成接口清单”这种结构化收集层面。这些东西有用但离真正的开发文档差太远。业务方想知道的不是这个方法叫什么名字而是这段逻辑扣了哪些单据、校验了什么状态、冲销时会不会带出历史记录。传统工具读不懂业务所以产出的东西大家不爱看看了也解决不了问题。还有一个容易被忽略的问题文档和代码是分离的。写好的 Word 放在共享盘里过两个月连路径都找不到了算力更集中一点的团队可能建了 Wiki但更新维护又变成新的负担。文档离代码越远维护动力就越低最后的结果永远是文档欠账越来越多直到项目组集体选择性遗忘。1.2 ZLLM 到底解决什么问题我做 ZLLM 这件事核心就是想解决上面三个问题没人写、写不全、不更新。思路不复杂把大模型接进 SAP 系统让它直接读取当前开发对象的源码理解对象名称、字段语义、方法调用关系然后生成一份业务向的说明文档。这份文档可以落到本地 Markdown可以存进自建表也可以生成源码注释的预览片段由开发者决定要不要写回代码里。为什么说是“理解”因为大模型对 ABAP 代码的语义推断能力远超传统的静态分析工具。给它一个函数名Z_MM_GOODS_MOVEMENT_POST再给它一段调用了 BAPI_GOODSMVT_CREATE 的代码它能推断出这是一个物料过账逻辑能进一步解释校验了哪些抬头字段、异常分支返回了什么消息、以及调用方需要预先准备哪些数据。这种输出已经不是“文档模板”的级别而是接近一个资深顾问在阅读代码后写的解释。ZLLM 的目标用户很明确传统 ABAP 开发顾问、SAP 业务分析师、负责系统交接和知识沉淀的团队以及那些被“补文档”折磨过无数次的人。它不追求替代人工评审而是把最耗时间的“初稿”工作接过去让人把精力放在审核和修正上。1.3 为什么强调“标准入口”再强的工具如果让开发者离开日常工作界面打开另一个网页或客户端使用率就会断崖式下降。这是我在多个项目里验证过的规律。ABAP 开发者的日常就是 SE80、SE24、SE38如果生成文档这件事要跳到一个外部工具里做哪怕流程只多两步两周后它也会被遗忘。所以我在设计 ZLLM 的时候选定了一个原则工具必须长在开发环境里。开发者在 SE80 里看到一个程序复制对象名打开 ZLLM 事务码粘贴点击生成一份文档就出来了。整个过程不需要离开 SAP GUI不需要安装额外桌面软件也不需要在浏览器和 SAP 之间来回切换。有一点必须说实话传统 SAP GUI 的 SE80 并没有提供官方菜单扩展点所以我做的“标准入口”是一个自开发事务码作为准入口。如果你是 ADTEclipse 下的 ABAP 开发工具用户体验会更接近“真正长在标准入口里”可以在项目资源管理器的上下文菜单中挂一个“生成文档”的动作直接读取当前选中对象并触发 ZLLM 类。文章中我会把这两种路径都讲清楚方便不同环境的团队选择。2. ZLLM 的整体架构设计与技术选型2.1 架构总览一个类、一张配置表、一个入口事务整个 ZLLM 工具链说到底只有三个核心建设对象我用一句话概括一个类负责干活一张表负责配置一个事务码负责入口。类是ZCL_LLM_DOC_GENERATOR里面封装了读取源码、构造 Prompt、调用大模型接口、解析返回结果、落地文档五个动作。配置表叫ZLLM_CONFIG结构很简单三个字段配置项、配置值、说明。API Key、模型名称、请求超时时间、温度参数全部放在这张表里。入口事务码是ZLLM_DOC界面上提供一个文本框和一个按钮输入对象类型和对象名点执行就开始生成。这里有一个选型上的关键决策我没有把 AI 能力封装成 BADI 或者用户出口而是做成了一个独立的类。原因很简单类的复用性最强后续不管是要扩展成批量生成、还是接入 CI/CD 流水线、或者给 ADT 插件调用都是增加一个调用方不需要动核心代码。这种“核心类 周边入口”的结构是我在多个自动化项目里验证下来最容易维护的形态。2.2 为什么用 SM59 HTTP Destination 而不是外挂中间件ABAP 程序调用外部 HTTP 服务标准做法是通过 SM59 配置一个 Destination然后在代码里用CL_HTTP_CLIENT根据 Destination 创建客户端。ZLLM 一开始也考虑过外挂中间件就是单独部署一个 Java 或 Python 服务由它去对接大模型 APISAP 只跟中间件通信。后来我把这个方案否掉了原因有几个。第一多一个中间件就多一个运维节点SAP 系统本身有严格的传输和权限控制而中间件的部署、监控、日志、安全补丁全都需要另找团队负责。第二SAP 到中间件、中间件到大模型链路多一跳排查问题时要跨越两个系统边界相当痛苦。第三SM59 本身已经解决了 URL 管理、SSL 证书、超时配置这些事我们没有理由再封一层。当然如果你的企业有统一的安全网关要求所有出网请求必须经过固定的接入服务那中间件方案就是刚需。这种情况下仍然可以把 ZLLM 的请求指向网关地址核心类不用改变的只是 SM59 里的目标主机和路径。这也是我坚持用 Destination 而不是在代码里硬编码 URL 的原因把网络细节留在配置层代码永远只关心业务。2.3 核心流程解析ZLLM 生成文档的主流程拆开看只有四个动作读取源码、构造 Prompt、调用大模型、解析并落地。整个过程看起来简单但每一步都有不少细节。读取源码这一步最烦人的不是代码本身而是不同类型对象的读取方式不一样。程序可以用READ REPORT函数模块可以用FUNCTION_READ类方法则需要先读取类池再用方法签名切分接口、CDS 视图又是另一种方式。所以我在类里做了一个对象类型的判断传入什么类型就走哪个分支这个在后面代码部分详细展开。构造 Prompt 是决定输出质量的关键环节。Prompt 里至少要包含对象类型、对象名、源码、输出格式要求。如果有团队偏好的文档模板也可以把它拼进 Prompt让大模型按模板输出。我的经验是给大模型一个“人设”和明确的输出约束比单纯丢一段代码进去效果好非常多。调用大模型就是标准 HTTP POST请求体是 JSON返回体也是 JSON。解析时用/UI2/CL_JSON把响应转成内表或者结构取出文本字段再交给下一步落地。这里有个常见的坑就是有些模型会在正常 JSON 前后加 Markdown 代码块标记不清理直接解析会报错这个在排查章节里细说。2.4 Prompt 设计的切入点让 LLM 看懂 ABAP很多人对接大模型时Prompt 写得非常随意丢一段代码就说“帮我写文档”。这样输出的东西不是太空就是胡编根本没法用。我总结了三个让模型懂 ABAP 的要点。第一给身份。系统人设里必须明确告诉模型“你是一名资深的 SAP ABAP 开发顾问”这比“你是一个 AI”出来的内容专业度要高一个量级。第二给上下文。不要把源码裸丢进去要告诉模型这个对象是程序、是函数、还是类方法在什么场景下被调用。比如一段 BDC 代码如果只是看代码模型只知道它在填屏幕如果你告诉它这是“货物移动过账的批导程序”它就能把代码和业务串起来。第三给格式要求。我在 Prompt 里要求模型必须返回 JSONJSON 里包含业务概述、逻辑步骤、入参出参、异常处理和注意事项每个字段都有明确说明。如果要进一步压榨质量可以上 few-shot 的思路在 Prompt 里附带一段“标准示例文档”让模型模仿样例的写法和语气。这个方法对文档风格统一特别有帮助尤其是团队已经有了固定模板的时候把模板塞进 Prompt就能让每次生成的结果都长成同一种样子。3. 核心代码实现从源码读取到文档写回3.1 读取对象源码与元数据代码实现的第一步是拿到要写文档的对象的完整源码。对于程序最简单的方法是READ REPORT这个语句可以直接把 ABAP 程序源码读入内表。对于函数模块可以用FUNCTION_READ它返回函数源码、导入导出参数、异常列表。对于类我会读取类池程序就是那个名长得像CL_类名CP的 INCLUDE然后按METHOD ... ENDMETHOD做切分把每个方法单独抽出来。这段逻辑我封装成了GET_SOURCE方法入参是对象类型和对象名返回源码字符串表。代码大致是这样的METHOD get_source. DATA: lt_source TYPE TABLE OF string. CASE iv_obj_type. WHEN PROG. READ REPORT iv_obj_name INTO lt_source. WHEN FUNC. CALL FUNCTION FUNCTION_READ EXPORTING functionname iv_obj_name IMPORTING programname DATA(lv_prog) TABLES source lt_source. IF sy-subrc 0. MESSAGE 函数模块读取失败 TYPE E. ENDIF. WHEN CLAS. SELECT SINGLE clsname INTO DATA(lv_clsname) FROM seoclskey WHERE clsname iv_obj_name. IF sy-subrc 0. DATA(lv_pool) |CL_{ iv_obj_name }CP|. READ REPORT lv_pool INTO lt_source. ENDIF. ENDCASE. rt_source lt_source. ENDMETHOD.类方法的切分我单独写了一个辅助方法逻辑是先找到METHOD 方法名这一行再找到对应的ENDMETHOD中间的内容就是方法源码。写这个切分器的时候要注意一点ABAP 方法里可能会嵌套调用另一个方法但不会嵌套METHOD...ENDMETHOD所以按标志字匹配是不会被嵌套干扰的放心用。3.2 构造 Prompt 与请求体拿到源码之后下一步就是把源码、对象信息和输出要求组装成一个完整的 Prompt。我建议用 ABAP 7.40 以后的字符串模板来拼可读性好也不容易漏掉换行符。Prompt 的结构我是这样设计的先是一段系统人设再是对象信息再是源码最后是输出格式要求。METHOD build_prompt. DATA(lv_newline) cl_abap_char_utilitiesnewline. DATA(lv_source) concat_lines_of( table it_source sep lv_newline ). rv_prompt |You are a senior SAP ABAP consultant.{ lv_newline }| |Please analyze the following ABAP code and generate a development document.{ lv_newline }| |Object type: { iv_obj_type }{ lv_newline }| |Object name: { iv_obj_name }{ lv_newline }| |Return a JSON object with these fields:{ lv_newline }| |- summary: one-line function summary{ lv_newline }| |- business_logic: step-by-step explanation of business logic{ lv_newline }| |- parameters: list of imports, exports, changing, tables{ lv_newline }| |- exceptions: exception information{ lv_newline }| |- remark: important notes or risks{ lv_newline }| |Documentation language: Chinese.{ lv_newline }| |Only return JSON, no other text.{ lv_newline }| |abap|{ lv_newline }|{ lv_source }|{ lv_newline }||. ENDMETHOD.请求体则按大模型服务提供商的标准格式组装这里我用了 OpenAI 兼容的 messages 结构。很多服务商都支持这种格式如果你用的不是这个格式只需要改这一处。序列化用的是/UI2/CL_JSON注意设置 camel_case 模式不然字段名会被转成大写。DATA: ls_payload TYPE zbapi_llm_chat_payload, lt_messages TYPE STANDARD TABLE OF zbapi_llm_message. ls_payload-model gpt-4o-mini. ls_payload-temperature 0.3. ls_payload-max_tokens 2000. APPEND VALUE #( role system content You are an expert ABAP documentation writer. ) TO lt_messages. APPEND VALUE #( role user content lv_prompt ) TO lt_messages. ls_payload-messages lt_messages. DATA(lv_request_json) /ui2/cl_jsonserialize( data ls_payload pretty_name /ui2/cl_jsonpretty_mode-camel_case ).3.3 调用 LLM 并解析返回值调用外部接口的代码在 ABAP 里非常成熟了核心就是通过 SM59 里的 Destination 创建 HTTP 客户端然后设置请求方法、请求头和请求体发送并接收。这里有一个细节API Key 不要硬编码我建议放在ZLLM_CONFIG表里然后在代码里读取需要加密的话再加一层解密逻辑。METHOD call_llm. DATA: lo_http TYPE REF TO if_http_client. cl_http_clientcreate_by_destination( EXPORTING destination ZLLM_OPENAI IMPORTING client lo_http ). lo_http-request-set_method( if_http_requestco_method_post ). lo_http-request-set_header_field( name Content-Type value application/json; charsetutf-8 ). lo_http-request-set_header_field( name Authorization value |Bearer { lv_api_key }| ). lo_http-request-set_cdata( lv_request_json ). lo_http-send( ). lo_http-receive( ). DATA(lv_response) lo_http-response-get_cdata( ). lo_http-close( ). rv_response lv_response. ENDMETHOD.响应解析我用/UI2/CL_JSON反序列化到结构里然后取出choices[1].message.content这个字段。有些厂商直接在顶层返回文本有些厂商需要再往下取一层这块要根据实际返回结构调整。解析前一定要做一次清洗把可能存在的 Markdown 代码块标记去掉否则 JSON 转换会直接抛异常。3.4 文档落地的三种方式文档生成出来后怎么落地是我反复问过自己的问题。我最终实现了三种方式让使用者按场景选择。第一种最直接下载成本地 Markdown 文件。用GUI_DOWNLOAD把生成的文本写到前端电脑文件按“对象类型_对象名_时间戳.md”命名拿到就能丢进知识库或 README 里。第二种是存进自建表。我建了ZDOC_HEADER和ZDOC_ITEM两张表前者存对象信息、生成时间、生成人后者存文档内容。这种方式的好处是文档跟着系统走后续可以写一个报表把所有对象的文档集中展示还可以做版本管理。第三种是生成源码注释预览。我会把文档内容套上 ABAP 注释前缀展示在编辑器屏幕上开发者觉得没问题手动粘进代码头部。这种方式风险最低我后续会在这一篇里明确推荐。写回源码这一步我始终不建议做成全自动。大模型偶尔会脑补出不存在的业务逻辑如果直接激活进生产代码这个风险没人担得起。所以 ZLLM 的默认策略永远是“生成文档人工确认再决定要不要写回”。4. 实操配置让 ZLLM 在系统里跑起来4.1 SM59 目的地配置细节要让 ABAP 程序能调到大模型的 API先得在 SM59 里配好 HTTP Destination。我的配置习惯是名称只允许大写字母和下划线比如ZLLM_OPENAI因为老版本 ABAP 在某些函数里对目的地名称大小写敏感踩过一次坑之后再也不用小写了。在 SM59 里创建连接类型选 GHTTP 连接技术设置里填主机名和端口。这里的主机名填你实际要调用的 API 服务地址如果是 OpenAI 兼容的服务一般是api.example.com这种格式。服务路径不要填错路径通常指向/v1/chat/completions或者厂商提供的具体接口位置这个路径在代码里可以通过request-set_header_field( name ~request_uri value ... )单独指定我更喜欢在 SM59 里配好基础路径代码里只保留相对路径分工更清晰。SSL 选择“Active”端口填 443。配置完成后强烈建议先用事务码SM59里的“连接测试”按钮验证一下网络连通性再进入代码调试。连接测试能帮你快速排除的是证书问题还是地址问题这一步能省不少时间。4.2 SSL 证书与权限配置ABAP 系统访问 HTTPS 地址必须处理 SSL 证书。如果目标服务用的是正规 CA 证书通常只需要在 STRUST 里把根证书导入对应的 SSL Client 证书存储。我遇到最多的问题是某些企业内的请求会被内部网关替换证书这时就得把企业网关的证书一并导入。具体的路径是 STRUST → 双击 SSL client(Standard) 或 SSL client(Anonymous) 节点 → 导入证书。导入之后记得刷新并重新打开 SM59 测试。权限方面调用 RFC/HTTP Destination 需要S_RFC权限执行程序需要权限对象S_PROGRAM。如果你们公司有统一的权限管控建议给 ZLLM 单独建一个权限角色不要直接塞给所有顾问。另外ZLLM_CONFIG表里放的是 API Key这类敏感数据必须有独立的权限对象保护不能让普通用户随便 SE16N 就能查到。我在项目里给这个表加了一个自定义权限对象只有指定角色能维护配置。4.3 从 SE80 发起生成的两种操作路径使用路径上我用两种方式把 ZLLM 真正“塞进”了开发日常工作流。第一种SAP GUI 用户在 SE80 里选中任意对象按组合键把对象名复制到剪贴板然后打开 ZLLM_DOC 事务码粘贴对象名点击生成。对象类型的选择可以用下拉框程序、函数模块、类方法、接口都可以只要在后端类里加了对应的类型解析逻辑就行。第二种ADT 用户。我的做法是开发了一个 Eclipse 插件通过扩展点在项目资源管理器上挂了一个“生成 ABAP 文档”菜单项。点击后插件读取当前选中的对象类型和名称调用同一个 ABAP 类生成文档并把结果打印到 Eclipse 的 Console 视图。这个路径的体验比事务码顺滑很多但需要额外的插件开发维护成本建议对 ADT 有标准的团队再上。我个人的建议是如果你们团队大部分人还在 SAP GUI 上先做事务码入口就足够如果团队已经全面切到 ADT那就直接做插件体验会好一个档次。5. 常见问题与排查速查表5.1 HTTP 调用失败的排查ZLLM 上线之后最常被问的就是“为什么调用失败”。我把这些问题整理成了一张排查表基本覆盖了所有常见场景。错误现象可能原因排查动作连接测试报“主机无法访问”SM59 主机名拼错或网络不通核对主机名检查域名解析用事务码 SM59 重测报证书错误SSL_ERRORSTRUST 证书缺失或被更换重新导入根证书确认 SSL Client 证书存储报 401/403API Key 错误或没有调用权限检查 ZLLM_CONFIG 表里的 Key确认账户状态报 404请求路径或方法不对核对 SM59 路径和代码里 set_method 是否为 POST报请求超时大模型响应太慢或网络不稳定拉长 HTTP timeout检查代码里是否设了超时参数HTTP 调用还有一个隐蔽问题很多企业防火墙会对长时间未响应的连接做拦截普通 HTTP 超时设置是几十秒大模型生成长文档时可能超过这个时间。我的做法是在代码里把 timeoute 设置放宽到 120 秒但这个值也要根据实际模型服务能力调整不是越长越好。5.2 JSON 解析与字符集问题JSON 解析报错是排查中的高频问题。最常见的坑是我在前面说过的那一个模型在返回内容的外面套了一层 Markdown 代码块标记拿这种内容直接去/UI2/CL_JSON反序列化必报错。我在代码里做了一个净化函数把开头的 “json” 和结尾的 “” 全部替换掉然后再解析。虽然看起来笨但非常管用。另一个高频问题是中文乱码。ABAP 系统默认编码和外部 API 的 UTF-8 编码不一致时返回的中文会变成一串乱码。解决方法是设置 HTTP 请求头里的字符集为 UTF-8并且在读取响应时用CL_ABAP_CONV_CODEPAGE做转换。注意发送请求和接收响应两边都要处理只处理一端的话仍然会有问题。5.3 源码读取受限与权限问题ZLLM 读取源码时可能碰到一个限制标准函数FUNCTION_READ和READ REPORT在读取某些系统对象时会提示权限不足或者读取到的源码为空。这通常不是 ZLLM 本身的逻辑问题而是 SAP 对标准软件开发包的保护。解决办法是不要对系统标准对象执行文档生成只在自定义开发对象上使用这个工具。如果团队里有人反馈“生成出来内容为空”优先让他检查对象名是不是复制的完整名称。比如类方法在 SE24 里显示为CLASS-METHOD的格式我的程序要求拆成两个字段分别输入有些人会把整串塞进对象名自然取不到源码。我在界面上加了一个说明允许输入CLAS/METHOD这种格式然后自动拆分减少这类使用错误。5.4 生成内容质量不佳的调优手段内容质量不行通常不是模型不行而是 Prompt 不够好。这是我和很多初次使用者讨论后得出的共同感受。比如你问它“帮我写文档”它会写出一堆正确但没用的套话你告诉它“请分析这段代码里 IF 条件为什么存在考虑 BDC 调用可能出现的错误场景”输出就会立刻变得具体。我的调优顺序是第一把 Prompt 里的对象信息补足尤其是业务场景说明第二降低 temperature 参数让它少一点发挥多一点稳定第三对大对象分段生成一个上千行的程序一次性塞给模型它的注意力会被分散分段摘要之后再做合并效果会好很多第四如果文档风格要非常贴合团队模板就把模板塞进 Prompt 里让模型仿写。这些手段组合用下来基本能把质量拉到“可审核”的基线以上。6. 实战心得与后续扩展6.1 落地过程中最大的三个心得这套方案我从概念验证到真正放进 ABAP 日常前后迭代了三个版本有几个心得是排了很多坑才得出来的。第一不要追求全自动。最初我在想既然大模型都能写文档了干脆让它生成完之后自动写回源码注释这样不是一步到位么后来发现不行。模型偶尔会一本正经地编造一些不存在的业务规则如果直接写进代码这些错误就变成了“官方文档”比没有文档更危险。所以 ZLLM 的默认路径永远是先预览、再人工确认、最后写回这个流程不能省。第二文档一定要和代码关联。把文档存在一个独立的 Word 文件里和存在自建表里两个方案我已经都试过。结果是存在自建表里的文档由于可以通过对象名反查使用率明显高得多。开发者愿意维护的文档一定是放得离代码最近的地方最好一眼就能找到。第三API Key 的管理要提前考虑。一开始我把 Key 放在常量里结果代码一传输Key 也跟着走理论上每个能下载源码的顾问都能看到。后来我改成存配置表、加权限对象这才安心。大模型服务的费用是跟着 API Key 走的如果你的 Key 被同事拿去其他地方乱用月底账单绝对会让你清醒。6.2 这套能力还能往哪些方向扩展ZLLM 只用来写开发文档说实话有点大材小用。我把底层思路跑通之后发现同样的“读源码、构 Prompt、调模型、输出结构化内容”的模式可以复制到不少场景。比如自动生成 BAPI 或 RFC 的接口说明文档这个可以直接把函数模块的导入导出参数和异常抽出来让模型生成一份给外围系统开发人员看的接口文档省掉手写接口说明书的痛苦。再比如自动生成 BDC 录屏步骤文档把批导程序的 BDC 处理代码交给模型让它反推出批导流程每个屏幕填写了什么字段、对应什么业务含义这对业务培训资料编写非常有用。还可以生成测试建议清单模型看完代码后会提出哪些场景值得重点测、哪些分支容易出错这份清单可以贴在传输请求里给测试人员做参考。更进一步可以把 ZLLM 接到后台作业里每晚定时扫描指定开发包下新增或变更的对象自动生成增量文档第二天开发者只需要审核和修正。这其实就是把文档维护从“人来找 AI”变成了“AI 来找人”体验会再上一个台阶。还有一个小方向就是结合代码评审。现在 ZLLM 生成的文档里包含了“业务逻辑步骤”和“注意事项”这些内容可以直接作为代码评审的视频资料。评审人先把 AI 生成的说明过一遍再对照代码看发现模型没理解对或者理解漏了的地方往往就是真正需要重点review的地方。这是一个意外收获也是我觉得这套工具后续最值得打磨的方向。
返回列表