利用大语言模型辅助软件开发的实践方法


基本信息


导语

随着大语言模型(LLM)能力的持续进化,软件开发工作流正经历从“手工编写”到“人机协作”的深刻转型。本文作者结合自身实践,详细拆解了如何将 LLM 无缝融入编码环节,从而在保证代码质量的前提下显著提升交付效率。阅读此文,你将获得一套可落地的 AI 辅助编程方法论,学会如何构建提示词、调试模型输出,并重新定义工程师在现代技术栈中的核心角色。


评论

深度评论

文章核心评价:AI辅助编程下的开发范式重构

中心观点: 该文章探讨了软件开发模式从“语法构建”向“语义设计”的演进,主张开发者通过将机械性编码任务转移给AI模型,从而重新定义自身的核心职能与价值。

支撑理由与边界条件:

  1. 认知资源的重新分配

    • 支撑理由(基于文章逻辑): 文章指出利用LLM处理模式匹配类工作(如样板代码、API调用),可以让开发者将精力集中于系统架构与高阶逻辑设计。这种分工旨在提升系统设计的整体效率。
    • 反例/边界条件(客观事实): 在处理上下文高度依赖的遗留系统维护,或对确定性要求极高的底层代码(如内核驱动)时,受限于上下文窗口和模型幻觉,调试AI生成代码的时间成本可能高于直接手写。
  2. 自然语言作为抽象层级的提升

    • 支撑理由(作者观点): 文章暗示编程语言的抽象层级正在经历从Python等高级语言向自然语言的跃迁。Prompt被视为更高维度的逻辑描述载体,代码则成为这一过程的副产品。
    • 反例/边界条件(客观事实): 自然语言具有模糊性。在金融算法、加密协议等需要强类型约束和数学精确性的场景中,自然语言描述无法替代形式化验证,LLM生成的微小偏差可能导致严重后果。
  3. 开发者角色的转变:从编写者到审核者

    • 支撑理由(基于文章逻辑): 文章隐含了开发者需具备超越AI的代码审查能力。AI的引入并未降低技术门槛,反而对架构层面的把控能力提出了更高要求。
    • 反例/边界条件(客观事实): 对于初级开发者,若缺乏识别逻辑漏洞(如并发竞态条件)的能力,过度依赖AI可能导致系统中潜伏难以排查的安全隐患。

1. 内容深度:意图与实现的解耦

文章超越了单纯的技术工具使用层面,探讨了软件工程中“意图”与“实现”的分离。在AI辅助开发模式下,意图由开发者通过自然语言定义,实现细节由模型填充。这种论证触及了开发流程的本质变化。不过,文章在讨论LLM处理长链条复杂逻辑推理时的可靠性(如“遗忘”问题)时,论述略显乐观。

2. 实用价值:工作流的优化策略

对于资深工程师,文章提出的方法论具有较高的参考价值。它提供了一套明确的任务分配策略:将语法检查、API查阅等重复性工作外包给AI,从而优化现有工作流。然而,对于初学者而言,直接跳过基础代码编写环节可能会影响其对计算机科学底层逻辑的理解,导致知识体系的断层。

3. 创新性:代码角色的再定义

文章提出了“代码即缓存”的观点,即代码只是机器执行的中间产物。在AI辅助模式下,开发者直接操作的是需求与逻辑,代码由AI自动生成与管理。这一观点挑战了传统的基于文本编辑器的开发流程,转向了对话式生成与差异化管理结合的新模式。

4. 逻辑结构与可读性

文章遵循“问题-解决方案-案例-反思”的结构,逻辑链条清晰。从传统编码的痛点切入,引入LLM作为解决方案,最后落脚于开发者角色的转变。这种叙事方式符合工程师的阅读习惯,论证过程较为严密。

5. 行业影响:评价体系的潜在变革

文章反映了行业标准的潜在转变。随着AI工具的普及,单纯的“代码量”考核将逐渐失效,行业可能更倾向于评估“系统吞吐量”和“问题解决效率”。这预示着开发者群体可能出现分化:一端是能够驾驭AI进行系统架构设计的开发者,另一端是仅能进行简单代码修补的操作人员。

6. 风险与争议:技术债务与合规性

  • 隐形技术债务: AI生成的代码可能存在逻辑微瑕或性能瓶颈(如错误的并发锁),这类“看似正确”的代码往往比人类手写的烂代码更难排查,容易积累隐形技术债务。
  • 版权与合规: 文章未深入探讨LLM生成代码的版权归属及合规风险(如涉及开源协议冲突或Copilot相关的法律诉讼风险),这是实际落地中不可忽视的因素。

代码示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 示例1:使用LLM生成代码补全
def generate_code_completion(prompt, max_tokens=100):
    """
    使用LLM生成代码补全
    :param prompt: 输入的代码片段或描述
    :param max_tokens: 生成的最大token数
    :return: 生成的代码补全
    """
    # 模拟LLM API调用(实际使用时替换为真实API)
    response = f"# LLM生成的代码补全:\n{prompt}  # 这里是自动补全的部分"
    return response

# 测试示例
print(generate_code_completion("def fibonacci(n):"))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 示例2:使用LLM进行代码审查
def review_code(code_snippet):
    """
    使用LLM进行代码审查
    :param code_snippet: 需要审查的代码
    :return: 审查建议
    """
    # 模拟LLM代码审查(实际使用时替换为真实API)
    review = f"""
    代码审查结果:
    1. 潜在问题: {code_snippet[:20]}... 可能存在性能问题
    2. 建议: 考虑使用更高效的算法
    3. 安全性: 检查输入验证
    """
    return review

# 测试示例
code = "for i in range(1000000):\n    x = i * i"
print(review_code(code))
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 示例3:使用LLM生成单元测试
def generate_unit_tests(function_code):
    """
    使用LLM生成单元测试
    :param function_code: 需要测试的函数代码
    :return: 生成的测试代码
    """
    # 模拟LLM生成测试(实际使用时替换为真实API)
    test_code = f"""
import unittest

def test_{function_code.split('(')[0].strip()}():
    # 测试正常情况
    assert {function_code.split('(')[0].strip()}(5) == expected_value
    
    # 测试边界条件
    assert {function_code.split('(')[0].strip()}(0) == 0
    
    # 测试异常情况
    with pytest.raises(ValueError):
        {function_code.split('(')[0].strip()}(-1)
"""
    return test_code

# 测试示例
func = "def calculate_square(n):\n    return n * n"
print(generate_unit_tests(func))

案例研究

1:某金融科技初创公司(内部效能提升)

1:某金融科技初创公司(内部效能提升)

背景: 该公司后端团队主要使用 Python 和 Go 开发微服务架构。团队规模较小,但面临繁重的开发任务,需要维护遗留系统并快速迭代新功能。

问题: 开发人员在编写单元测试和复杂的 SQL 迁移脚本上耗费了大量时间。由于业务逻辑复杂,编写覆盖全面的测试用例往往比编写业务代码本身更耗时,导致测试覆盖率长期不达标,且容易在 SQL 语法上出错。

解决方案: 团队引入了 GitHub Copilot 作为结对编程助手。在开发过程中,工程师编写核心业务逻辑函数,然后通过自然语言注释引导 LLM 生成边界条件测试用例。同时,利用 LLM 将描述性的数据需求直接转换为 PostgreSQL 的存储过程和迁移脚本。

效果: 单元测试的编写时间缩短了约 50%,测试覆盖率从原来的 65% 提升至 90% 以上。开发人员能够将更多精力集中在架构设计和核心业务逻辑上,而非重复性的样板代码。此外,SQL 脚本的语法错误率显著下降,减少了数据库回滚的次数。


2:某中型 SaaS 企业的遗留系统迁移

2:某中型 SaaS 企业的遗留系统迁移

背景: 该企业拥有一个运行超过 10 年的大型单体应用,核心逻辑由数万行 C# 代码组成,且文档缺失。原开发团队已大部分离职,现任团队对业务逻辑理解不深。

问题: 由于代码高度耦合且缺乏注释,新功能开发极其容易引入 Bug。团队计划将其重构为现代化的 .NET Core 微服务架构,但理解旧代码的依赖关系和业务流程成为最大的瓶颈。

解决方案: 技术团队利用具备代码分析能力的 LLM(如 GPT-4 或 Claude 3.5 Sonnet)辅助代码审查。他们将大型代码文件分段输入给 LLM,要求其“解释这段代码的意图”并“生成详细的伪代码流程图”。在重构阶段,工程师通过提示词让 LLM 将特定的 C# 类转换为更具现代特性的语法,并自动生成对应的接口文档。

效果: 团队理解旧代码逻辑的速度提升了 3 倍以上,原本预计耗时 6 个月的知识梳理和重构准备阶段缩短至 2 个月。LLM 生成的流程图帮助团队识别出了多个潜在的死锁风险和冗余逻辑,使得迁移后的系统性能更加稳定。


3:独立开发者的全栈应用开发

3:独立开发者的全栈应用开发

背景: 一位独立开发者希望构建一个基于浏览器的 PDF 处理工具,需要前端界面、后端 API 以及文件处理逻辑。该开发者擅长前端设计,但对后端 Node.js 和文件流处理相对生疏。

问题: 开发者对如何使用 TypeScript 操作文件流、配置 multer 中间件以及处理复杂的二进制数据转换感到棘手。通常需要频繁查阅文档和 Stack Overflow,开发节奏经常被打断。

解决方案: 开发者使用 Cursor(集成了 LLM 的 IDE)进行开发。在遇到不熟悉的 API 时,直接通过 IDE 的“Chat”功能描述需求,例如:“写一个 Express 中间件,用于验证上传的文件是否为 PDF,并限制大小为 5MB”。LLM 实时生成代码片段,开发者直接审查并整合到项目中。

效果: 项目从概念到 MVP(最小可行性产品)发布仅用了两周时间,而按照开发者原本的技术栈熟练度,预计需要一个月。开发者通过 LLM 快速跨越了技术盲区,不仅完成了功能,还通过 LLM 的解释学习了许多关于 Node.js 流处理的最佳实践。


最佳实践

最佳实践指南

实践 1:建立上下文感知的提示词工程

说明: 不要将 LLM 仅仅视为搜索引擎,而应将其视为一位需要背景信息的新团队成员。LLM 无法直接访问你的本地代码库、架构文档或业务逻辑。为了获得高质量的代码建议,必须提供足够的上下文,包括相关的代码片段、项目结构、技术栈约束以及具体的业务需求。

实施步骤:

  1. 在提问前,使用 @ 符号或文件引用功能(如果工具支持)将相关的代码文件添加到对话中。
  2. 明确告知模型你的技术栈(例如:Python 3.10, React 18, PostgreSQL)和编码风格偏好。
  3. 清晰地描述输入和输出的期望,而不仅仅是描述问题本身。

注意事项: 避免一次性粘贴过大的代码块,这可能会超出模型的上下文窗口或导致注意力分散。应只粘贴与当前任务最相关的部分。


实践 2:采用迭代式交互与细化

说明: 第一次生成的代码往往不是完美的。高效的 LLM 协作模式是“对话式”的,而非“一次性”的。通过持续的反馈、指正和细化,引导模型逐步接近正确的解决方案。这模拟了代码审查和重构的过程。

实施步骤:

  1. 如果生成的代码有误,不要重新开始,而是明确指出具体的错误行或逻辑漏洞。
  2. 要求模型解释其生成的代码逻辑,以验证其是否符合你的预期。
  3. 基于模型的输出,提出具体的修改要求,例如“将这个函数拆分为更小的函数”或“优化这个循环”。

注意事项: 保持耐心。有时模型会固执于错误的路径,此时尝试改变提问的角度或重新表述问题往往比直接纠正更有效。


实践 3:利用 AI 辅助编写测试代码

说明: 测试驱动开发(TDD)或至少是编写测试用例,是利用 LLM 的最佳场景之一。LLM 非常擅长根据业务逻辑生成边界条件测试、单元测试和模拟数据。这不仅能验证代码的正确性,还能防止未来的重构破坏现有功能。

实施步骤:

  1. 编写完核心功能后,将代码发送给 LLM,并要求“为这段代码编写全面的单元测试,覆盖正常情况和边界情况”。
  2. 如果使用特定的测试框架(如 Pytest, Jest),请在提示词中明确指定。
  3. 要求 LLM 生成测试用的模拟数据,确保数据多样性。

注意事项: LLM 生成的测试可能会通过断言一些显而易见的事实而忽略复杂的逻辑错误。务必人工审查生成的测试用例是否真正具有挑战性。


实践 4:使用 LLM 进行代码重构与文档化

说明: 阅读和理解复杂的遗留代码(Legacy Code)是非常耗时的。LLM 可以作为高级助手,帮助解释晦涩的代码、优化算法复杂度以及自动生成文档。这能显著降低代码维护的认知负担。

实施步骤:

  1. 选中一段难以理解的旧代码,要求 LLM “逐行解释这段代码的功能”。
  2. 询问 LLM “是否有更现代或更高效的方式重写这段代码,并保持功能不变”。
  3. 在完成功能开发后,将代码发送给 LLM,要求其“生成符合标准格式的 Docstring 或 API 文档”。

注意事项: 在进行重构建议时,确保 LLM 理解代码的副作用。对于涉及并发、数据库事务或底层系统调用的代码,要谨慎采纳重构建议。


实践 5:保持“人在回路”的验证机制

说明: 无论模型多么先进,它都会产生“幻觉”或生成看似合理但实际有漏洞的代码。开发者必须始终保持怀疑态度,将 LLM 视为初级开发者或助手,而不是权威。所有的代码合并都必须经过人工审查。

实施步骤:

  1. 不要盲目复制粘贴代码。阅读每一行生成的代码,确保你理解其逻辑。
  2. 在运行生成代码之前,手动检查变量名、函数调用和导入的库是否正确。
  3. 对生成的代码进行安全扫描,特别是涉及 SQL 查询、系统命令执行或数据处理的部分,防止注入漏洞。

注意事项: LLM 可能会编造不存在的库函数或 API。在实施前,务必查阅官方文档确认这些方法的真实存在性。


实践 6:构建私有知识库与定制化工作流

说明: 通用模型可能不了解你公司的内部库、专用协议或特定的业务规则。通过建立包含内部文档、API 规范和常见代码模式的私有知识库,可以显著提升 LLM 在特定场景下的表现。

实施步骤:

  1. 将内部的 API 文档、架构设计文档和常用代码片段整理成文本,作为“上下文”随时准备投喂给模型。
  2. 创建一套标准化的提示词模板,用于重复性任务(如“创建一个新的 CRUD API 端点”),其中包含项目规范。
  3. 记录下那些能产生高质量结果的提示词,形成团队内部的“提示词库”。

注意事项: 在向


学习要点

  • 基于您提供的背景信息(Hacker News 上关于“如何使用 LLM 编写软件”的讨论),以下是总结出的关键要点:
  • 将 LLM 视为初级开发者或结对编程伙伴,而非全知全能的架构师,必须由人类开发者主导系统设计和逻辑验证。
  • 采用“自下而上”的增量开发模式,先让 AI 生成底层的小型函数或单元测试,再逐步组装成复杂系统。
  • 优先编写详尽的提示词来生成测试用例,通过测试驱动开发(TDD)来确保 AI 生成的代码符合预期并具备鲁棒性。
  • 掌握提示词工程是核心技能,通过提供清晰的上下文、具体的示例和约束条件,能显著提高代码生成的准确率。
  • 利用 LLM 处理繁琐的遗留代码迁移、编写样板代码或解释陌生代码库,以释放精力用于核心业务逻辑。
  • 建立严格的代码审查习惯,逐行检查 AI 输出的每一行代码,警惕 AI 可能产生的幻觉或引入的安全漏洞。

常见问题

1: 目前主流的 LLM(如 GPT-4 或 Claude 3)在编写软件时主要扮演什么角色?它们真的能独立完成整个项目吗?

1: 目前主流的 LLM(如 GPT-4 或 Claude 3)在编写软件时主要扮演什么角色?它们真的能独立完成整个项目吗?

A: 目前主流的大语言模型(LLM)主要扮演辅助工具的角色,而非独立的开发者。它们通常在以下场景中被使用:

  1. 代码片段生成:根据注释或函数名生成常规的函数逻辑。
  2. 代码重构与翻译:将代码从一种语言转换为另一种,或优化现有代码结构。
  3. 错误排查辅助:通过分析错误日志或代码片段,提供潜在的问题排查思路。

目前,LLM 尚不具备独立完成复杂软件项目的能力。在处理长上下文时可能会丢失细节,且在系统架构设计、业务逻辑的深层理解以及多模块间的隐式依赖处理上,仍存在局限性。在实际开发流程中,通常由人类工程师负责架构设计和最终决策,LLM 负责具体的实现细节辅助。


2: 使用 LLM 编写代码时,如何处理数据隐私和敏感信息泄露的风险?

2: 使用 LLM 编写代码时,如何处理数据隐私和敏感信息泄露的风险?

A: 在使用基于云的 LLM 服务时,数据隐私是一个需要重点考虑的问题。为了降低风险,开发者通常采取以下策略:

  1. 数据脱敏:在将代码发送给 LLM 之前,移除 API 密钥、用户个人身份信息(PII)或核心业务逻辑等敏感数据。
  2. 使用本地模型:利用 LLaMA 3、CodeLlama 或 Mistral 等开源模型,在本地机器或私有服务器上运行推理。这种方式可以确保数据不传输给第三方。
  3. 企业版协议:使用提供企业级服务条款的版本(如 ChatGPT Team/Enterprise),这些协议通常明确承诺不使用用户数据进行模型训练。

3: 在使用 LLM 辅助编程时,如何避免产生“幻觉”代码(即看起来逼真但实际不存在或错误的 API 调用)?

3: 在使用 LLM 辅助编程时,如何避免产生“幻觉”代码(即看起来逼真但实际不存在或错误的 API 调用)?

A: “幻觉”是指模型生成的内容看似合理但实际上不准确。在编程场景下,可以通过以下方式缓解:

  1. 明确上下文:在 Prompt 中指定使用的库版本和具体框架(例如:“请使用 Pandas 2.0 的语法…”)。
  2. 要求提供依据:要求 LLM 在生成代码后提供官方文档链接或解释参数来源。
  3. 分步验证:避免一次性生成大量代码。应分模块生成,并编写单元测试进行验证。
  4. 使用 RAG(检索增强生成):利用结合了本地代码库索引的工具(如 Cursor 或 GitHub Copilot Workspace),这些工具基于项目实际存在的上下文生成代码,相比通用模型准确率更高。

4: 哪些编程语言或任务最适合与 LLM 协作,哪些比较困难?

4: 哪些编程语言或任务最适合与 LLM 协作,哪些比较困难?

A:

  • 适合协作的场景

    • Python:由于 Python 语法简洁、库丰富且训练数据量大,LLM 在数据分析、脚本编写和后端 API 方面的表现较好。
    • Web 前端:生成 HTML/CSS/React 组件通常较为顺利,因为代码结构相对标准化。
    • Go/Rust:在处理并发或内存管理的基础代码编写上,LLM 也能提供辅助。
  • 处理困难的场景

    • 遗留代码维护:涉及缺乏文档的旧系统(如旧版 C++ 或 COBOL),LLM 往往难以理解晦涩的上下文。
    • 底层驱动开发:涉及特定硬件寄存器操作的代码,LLM 可能会生成针对错误芯片型号或不兼容的代码。

5: 既然 LLM 可以辅助编程,是否还需要深入学习算法和数据结构?

5: 既然 LLM 可以辅助编程,是否还需要深入学习算法和数据结构?

A: 是的,基础知识依然重要。虽然 LLM 可以生成常见的算法实现,但:

  1. 代码审查:开发者需要具备扎实的知识才能判断 LLM 生成的代码是否高效、是否存在逻辑错误或边界条件问题。
  2. 提示词工程:对技术原理的理解越深,越能准确地描述需求,从而获得更符合预期的代码。
  3. 系统设计:LLM 擅长处理局部代码,但如何构建高性能、低延迟的整体系统架构,仍然依赖于人类对复杂度和数据结构的理解。

6: 常用的 AI 编程工具有哪些?它们之间有什么区别?

6: 常用的 AI 编程工具有哪些?它们之间有什么区别?

A:

  1. GitHub Copilot:目前普及度较高的工具,以 IDE 插件形式集成,能够根据当前文件内容自动补全代码。
  2. Cursor:基于 VS Code 二次开发的编辑器,深度集成了 AI 对话功能,支持对整个代码库进行语义搜索和重构。
  3. ChatGPT/Claude (Web界面):适合进行技术方案调研、算法解释或生成不依赖特定项目上下文的通用代码片段。
  4. **JetBrains AI /

思考题

## 挑战与思考题

### 挑战 1: 上下文感知的代码生成

问题**: 在使用 LLM 辅助编写代码时,直接复制粘贴生成的代码往往会导致上下文丢失。请设计一种提示词策略,确保 LLM 能够理解你现有项目的文件结构,并生成符合现有目录规范的代码,而不是孤立的代码片段。

提示**: 考虑如何在对话开始时向模型提供“元数据”,或者利用 LLM 支持的文件引用功能。思考如何描述文件之间的依赖关系。


引用

注:文中事实性信息以以上引用为准;观点与推断为 AI Stack 的分析。



站内链接

相关文章