别再让 AI 瞎改代码了!我把整个项目喂给 DeepSeek 后,AI 幻觉直接归零

11 阅读6分钟

正文

一、先上结论

把完整项目代码一次性喂给 AI,是目前对抗“AI 幻觉”最有效、最靠谱的方法,没有之一。

DeepSeek + “完整项目喂入法” = 几乎不翻车的 AI 编程助手。


二、一个扎心的真实场景

你有没有遇到过这种情况:

你:帮我把 userInfo 字段改成 profile
AI:好的,已修改 ✅
(实际结果:AI 把 userInfo、userinfo、user_info 全改了,还顺便重命名了你没提到的变量)

或者更崩溃的:

你:在这个页面加个搜索功能
AI:好的,已添加 🔍
(实际结果:样式崩了、接口调错了、分页逻辑也改坏了)

这就是 AI 幻觉——它太“聪明”了,聪明到会自己脑补不存在的逻辑。


三、我找到的解法:完整上下文法

核心思路:在提需求之前,先让 AI 完整“看”一遍你的整个项目。

具体操作(超级简单)

步骤操作
1运行脚本,自动生成 project_documentation.md
2把这个文件上传给 DeepSeek
3在同一个会话里提出你的具体需求
4如果对话太长,直接新开话题重新上传文档

为什么新开话题很重要?

当对话轮次过多(比如超过 10-15 轮),AI 的注意力会分散,容易出现“前面说过的东西后面忘了”的情况。这时候果断新开话题、重新上传文档,效果反而更好。

一句话总结:每次重要修改,都让 AI 重新“熟悉”一遍项目。


四、配套脚本:一键生成项目快照

我写了一个 Python 脚本,能在几秒内把整个项目转成 AI 能消化的 Markdown 文档。

脚本核心能力

  • ✅ 自动生成目录树
  • ✅ 收集 15+ 种代码文件(.cpp/.vue/.js/.py/.ts 等)
  • ✅ 按文件类型分组,语法高亮
  • ✅ 自动忽略 .git、node_modules 等无用目录
  • ✅ 多编码自动检测(UTF-8/GBK/Latin-1)

五、为什么这个方法能让 AI 幻觉“归零”?

AI 看到的内容可能的行为
只有零散的几段代码“用户可能想改这个?我猜一下” → 乱改一通 ❌
完整的目录结构 + 所有代码“我看到了完整的调用链和项目规范” → 精准修改 ✅

说白了:AI 不是神,它是靠信息做判断的。你给的信息越完整,它的判断就越准。


六、我的“最佳实践”总结(建议收藏)

  1. 每次重要任务前,都重新生成文档喂给 AI(不要依赖短期记忆)
  2. 对话超过 10-15 轮,果断新开话题(避免上下文污染)
  3. 先上传文档,再提需求(顺序别反了)
  4. 让 AI 输出修改方案后你再确认(不要直接让它改)
  5. 敏感项目注意脱敏(密钥、密码记得删掉)

七、一些心里话

我试过很多方法,最后沉淀下来的就是这套流程。

它不 fancy,但有效。

可能你会觉得“每次都要重新上传文档好麻烦”,但比起 AI 乱改代码后你花半小时 debug,这 10 秒钟的“麻烦”简直不值一提。

如果你也在用 AI 辅助编程,强烈建议试试这个方法。

真的,试一次你就回不去了。


八、互动

  • 你被 AI 幻觉坑过最惨的一次是什么?
  • 你有没有其他好用的“防幻觉”技巧?

欢迎评论区分享 👇


附录:完整脚本代码

# -*- coding: utf-8 -*-
"""
将当前目录下的文件结构及代码整合到Markdown文件
支持文件类型: .h, .cpp, .pro, .vue, .js, .ts, .jsx, .tsx, .yml, .yaml, .xml, .html, .py
"""

import os
import sys
from pathlib import Path
import fnmatch

def get_directory_tree(start_path, ignore_patterns=None):
    """
    获取目录树结构
    """
    if ignore_patterns is None:
        ignore_patterns = ['.git', '__pycache__', '*.pyc', '.idea', 'build', 'dist', 'node_modules']
    
    tree_lines = []
    
    def _walk(dir_path, prefix=""):
        # 获取当前目录下的所有项目
        try:
            items = sorted(os.listdir(dir_path))
        except PermissionError:
            return
        
        # 过滤掉忽略的项目
        items = [item for item in items 
                if not any(fnmatch.fnmatch(item, pattern) 
                          for pattern in ignore_patterns)]
        
        for i, item in enumerate(items):
            item_path = os.path.join(dir_path, item)
            is_last = (i == len(items) - 1)
            
            # 选择适当的前缀符号
            if is_last:
                tree_lines.append(f"{prefix}└── {item}")
                new_prefix = prefix + "    "
            else:
                tree_lines.append(f"{prefix}├── {item}")
                new_prefix = prefix + "│   "
            
            # 如果是目录,递归遍历
            if os.path.isdir(item_path):
                _walk(item_path, new_prefix)
    
    # 添加根目录名称
    root_name = os.path.basename(os.path.abspath(start_path))
    tree_lines.append(f"{root_name}/")
    _walk(start_path)
    
    return "\n".join(tree_lines)

def should_process_file(filename):
    """
    判断文件是否需要处理
    支持的扩展名: .h, .cpp, .pro, .vue, .js, .ts, .jsx, .tsx, .yml, .yaml, .xml, .html, .py
    """
    valid_extensions = [
        '.h', '.cpp', '.pro', '.vue', '.js', '.ts', '.jsx', '.tsx',
        '.yml', '.yaml', '.xml', '.html', '.htm', '.py'
    ]
    return any(filename.endswith(ext) for ext in valid_extensions)

def read_file_content(filepath):
    """
    读取文件内容
    """
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            return f.read()
    except UnicodeDecodeError:
        # 如果UTF-8解码失败,尝试使用其他编码
        try:
            with open(filepath, 'r', encoding='gbk') as f:
                return f.read()
        except:
            try:
                with open(filepath, 'r', encoding='latin-1') as f:
                    return f.read()
            except:
                return f"[无法读取文件: 编码不支持]"
    except Exception as e:
        return f"[读取文件时出错: {str(e)}]"

def generate_markdown(output_file="project_documentation.md"):
    """
    生成Markdown文档
    """
    current_dir = os.getcwd()
    dir_name = os.path.basename(current_dir)
    
    with open(output_file, 'w', encoding='utf-8') as md_file:
        # 写入标题
        md_file.write(f"# {dir_name} 项目文档\n\n")
        
        # 写入生成时间
        from datetime import datetime
        md_file.write(f"*生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n\n")
        
        # 写入目录树
        md_file.write("## 目录结构\n\n")
        md_file.write("```\n")
        md_file.write(get_directory_tree(current_dir))
        md_file.write("\n```\n\n")
        
        # 收集所有需要处理的文件
        files_to_process = []
        for root, dirs, files in os.walk(current_dir):
            # 忽略一些目录
            dirs[:] = [d for d in dirs if not d.startswith('.') 
                      and d not in ['__pycache__', 'build', 'dist', 'node_modules']]
            
            for file in files:
                if should_process_file(file):
                    full_path = os.path.join(root, file)
                    rel_path = os.path.relpath(full_path, current_dir)
                    files_to_process.append((rel_path, full_path))
        
        # 按文件类型和路径排序
        files_to_process.sort(key=lambda x: (os.path.splitext(x[0])[1], x[0]))
        
        # 写入文件内容
        md_file.write("## 源代码\n\n")
        
        if not files_to_process:
            md_file.write("*没有找到支持的文件类型*\n")
            md_file.write("*支持的文件类型: .h, .cpp, .pro, .vue, .js, .ts, .jsx, .tsx, .yml, .yaml, .xml, .html, .py*\n")
        else:
            # 按文件类型分组
            file_types = {
                '.pro': 'Qt项目文件',
                '.h': '头文件',
                '.cpp': 'C++源文件',
                '.vue': 'Vue组件',
                '.js': 'JavaScript文件',
                '.ts': 'TypeScript文件',
                '.jsx': 'React JSX文件',
                '.tsx': 'React TSX文件',
                '.yml': 'YAML配置文件',
                '.yaml': 'YAML配置文件',
                '.xml': 'XML文件',
                '.html': 'HTML文件',
                '.htm': 'HTML文件',
                '.py': 'Python文件'
            }
            
            # 定义分组顺序
            extensions_order = [
                '.pro', '.h', '.cpp', 
                '.vue', '.ts', '.tsx', '.js', '.jsx',
                '.yml', '.yaml', '.xml', '.html', '.htm',
                '.py'
            ]
            
            for ext in extensions_order:
                type_files = [(rel, full) for rel, full in files_to_process if rel.endswith(ext)]
                if type_files:
                    md_file.write(f"### {file_types.get(ext, ext)}文件\n\n")
                    
                    for rel_path, full_path in type_files:
                        # 写入文件名作为子标题
                        md_file.write(f"#### {rel_path}\n\n")
                        
                        # 写入文件内容
                        content = read_file_content(full_path)
                        
                        # 根据文件扩展名设置代码块语言
                        lang_map = {
                            '.h': 'cpp',
                            '.cpp': 'cpp',
                            '.pro': 'makefile',
                            '.vue': 'vue',
                            '.js': 'javascript',
                            '.ts': 'typescript',
                            '.jsx': 'jsx',
                            '.tsx': 'tsx',
                            '.yml': 'yaml',
                            '.yaml': 'yaml',
                            '.xml': 'xml',
                            '.html': 'html',
                            '.htm': 'html',
                            '.py': 'python'
                        }
                        lang = lang_map.get(ext, '')
                        
                        md_file.write(f"```{lang}\n")
                        md_file.write(content)
                        if content and not content.endswith('\n'):
                            md_file.write('\n')
                        md_file.write("```\n\n")
        
        # 写入统计信息
        md_file.write("## 统计信息\n\n")
        md_file.write(f"- 总文件数: {len(files_to_process)}\n")
        
        # 按扩展名统计
        ext_counts = {}
        for rel_path, _ in files_to_process:
            ext = os.path.splitext(rel_path)[1]
            ext_counts[ext] = ext_counts.get(ext, 0) + 1
        
        # 显示统计信息
        ext_names = {
            '.pro': 'Qt项目',
            '.h': '头文件',
            '.cpp': 'C++源文件',
            '.vue': 'Vue组件',
            '.js': 'JavaScript',
            '.ts': 'TypeScript',
            '.jsx': 'React JSX',
            '.tsx': 'React TSX',
            '.yml': 'YAML',
            '.yaml': 'YAML',
            '.xml': 'XML',
            '.html': 'HTML',
            '.htm': 'HTML',
            '.py': 'Python'
        }
        
        for ext, count in ext_counts.items():
            name = ext_names.get(ext, ext)
            md_file.write(f"- {name}文件 ({ext}): {count}个\n")
    
    print(f"文档已生成: {output_file}")
    print(f"共处理了 {len(files_to_process)} 个文件")
    print(f"支持的文件类型: .h, .cpp, .pro, .vue, .js, .ts, .jsx, .tsx, .yml, .yaml, .xml, .html, .py")

def main():
    """
    主函数
    """
    print("项目文档生成器 (支持C/C++/Qt/Vue/JavaScript/TypeScript/YAML/XML/HTML/Python)")
    print("=" * 80)
    
    # 可以自定义输出文件名
    output_filename = "project_documentation.md"
    if len(sys.argv) > 1:
        output_filename = sys.argv[1]
    
    generate_markdown(output_filename)

if __name__ == "__main__":
    main()