0
0
0

论文大师源码

职场区 3253582893 1月前
1716

源码获取:ym7k.com/11659/

论文大师源码:从科目选择到提纲生成的工程架构

引子:提纲生成是学术写作的"结构工程"

大多数人对 AI 论文写作的想象停留在"输入题目,输出全文"。这个想象忽略了一个关键事实:学术论文的核心难度不在于文字生成,而在于结构设计。

一篇一万字的论文,文字本身可能只占工作量的三成,剩下七成花在确定研究问题、梳理文献、设计论证框架、组织章节逻辑上。如果系统只负责"写",而把结构性工作留给用户,那它解决的只是一个次要问题。

"论文大师"的核心设计思路,正是从这个判断出发的:先解决科目选择,再解决题目输入;先解决大纲,再解决成稿;先解决结构,再解决文字。 它把论文写作拆解为“科目选择 → 题目输入 → 大纲生成 → 分章生成 → 整合润色”的流水线,每一步都有明确的输入输出和质量控制。

本文从科目分类的工程含义、题目解析的技术方案、大纲生成的结构化方法、不同学科大纲的差异化策略,到提纲的可编辑性与版本管理,展开这类系统的完整技术分析。

一、科目选择:为什么它不是简单下拉框

1.1 科目分类的工程意义

在"论文大师"的界面上,科目选择看起来只是一个下拉框。但从工程角度看,这个选择决定了后续所有生成逻辑的参数。

科目决定了论文的学术范式。 理工科论文强调实验数据和公式推导,论文结构通常是"引言-方法-实验-结果-讨论-结论"。人文社科论文强调理论辨析和文本解读,结构通常是"引言-文献综述-理论框架-论证-结论"。商科论文强调案例分析和实证研究,结构介于两者之间。

科目决定了文献引用的格式。 理工科常用 IEEE 或 APA 格式,人文社科常用 MLA 或 Chicago 格式,中文学术论文常用 GB/T 7714 格式。

科目决定了写作语言的风格。 理工科偏客观、简洁,避免修辞;人文社科允许一定的论述性语言。

因此,科目选择不是一个 UI 元素,而是生成参数的核心输入。

1.2 科目分类的数据模型

sql
CREATE TABLE `subject` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL COMMENT '科目名称',
  `code` varchar(50) NOT NULL COMMENT '科目编码',
  `parent_id` int(11) DEFAULT NULL COMMENT '父级科目',
  `level` tinyint(1) NOT NULL DEFAULT '1' COMMENT '层级 1/2/3',
  `discipline_type` varchar(20) NOT NULL COMMENT 'empirical/theoretical/review',
  `citation_style` varchar(20) NOT NULL DEFAULT 'gb7714' COMMENT '引用格式',
  `outline_template` text COMMENT '大纲模板JSON',
  `sort` int(11) NOT NULL DEFAULT '0',
  `status` tinyint(1) NOT NULL DEFAULT '1',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_code` (`code`),
  KEY `idx_parent` (`parent_id`),
  KEY `idx_discipline` (`discipline_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

discipline_type 字段是核心。它定义了该科目属于哪种学术范式,决定了后续大纲生成的模板选择。

1.3 科目树的构建

科目通常有三层结构:一级学科(如"计算机科学与技术")、二级学科(如"人工智能")、三级方向(如"自然语言处理")。用户选择到三级方向,系统据此选择最精确的模板。

php
<?php
// app/service/subject/SubjectService.php

namespace app\service\subject;

use think\facade\Db;

class SubjectService
{
    /**
     * 获取科目树
     */
    public function tree(int $parentId = 0): array
    {
        $subjects = Db::name('subject')
            ->where('parent_id', $parentId)
            ->where('status', 1)
            ->order('sort', 'asc')
            ->select()
            ->toArray();

        foreach ($subjects as &$subject) {
            $children = $this->tree($subject['id']);
            if (!empty($children)) {
                $subject['children'] = $children;
            }
        }

        return $subjects;
    }

    /**
     * 获取科目的生成配置
     */
    public function getGenerationConfig(int $subjectId): array
    {
        $subject = Db::name('subject')->where('id', $subjectId)->find();
        if (!$subject) {
            throw new \Exception('科目不存在');
        }

        // 向上追溯,合并父级配置
        $config = [
            'discipline_type' => $subject['discipline_type'],
            'citation_style' => $subject['citation_style'],
            'outline_template' => $subject['outline_template'],
        ];

        $parentId = $subject['parent_id'];
        while ($parentId) {
            $parent = Db::name('subject')->where('id', $parentId)->find();
            if (!$parent) break;

            // 子级未定义的配置继承父级
            if (empty($config['outline_template'])) {
                $config['outline_template'] = $parent['outline_template'];
            }

            $parentId = $parent['parent_id'];
        }

        return $config;
    }

    /**
     * 搜索科目
     */
    public function search(string $keyword, int $limit = 20): array
    {
        return Db::name('subject')
            ->where('status', 1)
            ->where('name', 'like', "%{$keyword}%")
            ->limit($limit)
            ->select()
            ->toArray();
    }
}

配置的向上追溯是关键设计。 三级方向可能没有自己的大纲模板,此时继承二级学科的模板;二级学科没有,继承一级学科的;一级学科没有,使用系统默认模板。这种层级继承减少了配置的重复。

二、题目输入:从自然语言到结构化参数

2.1 题目解析的工程挑战

用户输入的论文题目通常是一句自然语言,如"基于深度学习的图像超分辨率重建方法研究"。系统需要从中提取出结构化参数,用于后续的大纲生成。

题目解析需要提取的信息包括:研究对象(图像超分辨率重建)、研究方法(深度学习)、研究类型(方法研究)、研究问题(如何提升重建质量)。

2.2 基于 LLM 的题目解析

题目解析使用 LLM 完成,输出结构化的 JSON。

php
<?php
// app/service/outline/TitleParser.php

namespace app\service\outline;

class TitleParser
{
    /**
     * 解析论文题目
     */
    public function parse(string $title, array $subjectConfig): array
    {
        $prompt = $this->buildPrompt($title, $subjectConfig);
        $result = $this->callLLM($prompt);

        return $this->validateResult($result);
    }

    protected function buildPrompt(string $title, array $config): string
    {
        $disciplineType = $config['discipline_type'] ?? 'empirical';

        return <<<PROMPT
你是一个学术论文写作助手。请解析以下论文题目,提取结构化信息。

论文题目:{$title}
学科范式:{$disciplineType}

请提取以下信息,以 JSON 格式返回:
{
  "research_object": "研究对象(如:图像超分辨率重建)",
  "research_method": "研究方法(如:深度学习)",
  "research_type": "研究类型(method/application/theory/review)",
  "research_question": "核心研究问题(如:如何提升重建质量)",
  "keywords": ["关键词1", "关键词2", "关键词3"],
  "suggested_chapters": ["建议的章节标题1", "建议的章节标题2"]
}

要求:
1. 研究对象和研究方法必须从题目中提取,不要臆造
2. 研究问题需要根据研究对象和方法推断
3. 关键词应为学术术语,3-5 个
4. suggested_chapters 为 3-5 个核心章节建议

只返回 JSON,不要返回其他内容。
PROMPT;
    }

    protected function callLLM(string $prompt): array
    {
        // 调用 LLM,返回解析后的 JSON
        // 实际实现中需要处理 API 调用、重试、错误处理
        return [];
    }

    protected function validateResult(array $result): array
    {
        $required = ['research_object', 'research_method', 'research_type'];
        foreach ($required as $field) {
            if (empty($result[$field])) {
                throw new \Exception("题目解析失败:缺少 {$field}");
            }
        }
        return $result;
    }
}

题目解析的价值在于"锚定"。 生成的 JSON 作为后续大纲生成的上下文,确保大纲中的章节与题目中的研究对象和方法保持一致。没有这个锚定,LLM 生成的大纲可能偏离题目。

2.3 题目的合法性校验

题目解析之前,需要做基本的合法性校验:题目长度(10-50 字)、是否包含研究对象、是否为完整的学术表述。

php
<?php
// app/service/outline/TitleValidator.php

namespace app\service\outline;

class TitleValidator
{
    public function validate(string $title): array
    {
        $errors = [];

        $length = mb_strlen($title);
        if ($length < 8) {
            $errors[] = '题目过短,建议至少 8 个字';
        }
        if ($length > 60) {
            $errors[] = '题目过长,建议不超过 60 个字';
        }

        // 检查是否包含学术表述特征
        $academicKeywords = ['研究', '分析', '设计', '实现', '方法', '系统', '模型', '算法'];
        $hasAcademicKeyword = false;
        foreach ($academicKeywords as $kw) {
            if (mb_strpos($title, $kw) !== false) {
                $hasAcademicKeyword = true;
                break;
            }
        }
        if (!$hasAcademicKeyword) {
            $errors[] = '题目缺少学术表述特征(建议包含"研究""分析""设计"等词)';
        }

        // 检查是否包含明显非学术内容
        $nonAcademic = ['朋友圈', '抖音', '微博', '八卦'];
        foreach ($nonAcademic as $kw) {
            if (mb_strpos($title, $kw) !== false) {
                $errors[] = "题目包含非学术内容:{$kw}";
            }
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors,
        ];
    }
}

三、大纲生成:结构化方法

3.1 学科范式模板

不同学科范式对应不同的论文结构模板。

php
<?php
// app/service/outline/OutlineTemplates.php

namespace app\service\outline;

class OutlineTemplates
{
    /**
     * 实证研究型模板(理工科、商科实证)
     */
    public static function empirical(): array
    {
        return [
            ['key' => 'abstract', 'title' => '摘要', 'ratio' => 0.03],
            ['key' => 'introduction', 'title' => '引言', 'ratio' => 0.12, 'subs' => [
                '研究背景与意义',
                '国内外研究现状',
                '研究内容与方法',
                '论文结构安排',
            ]],
            ['key' => 'literature', 'title' => '文献综述', 'ratio' => 0.20, 'subs' => [
                '核心概念界定',
                '相关理论基础',
                '已有研究梳理',
                '研究空白与本文定位',
            ]],
            ['key' => 'method', 'title' => '研究方法', 'ratio' => 0.18, 'subs' => [
                '研究框架设计',
                '数据来源与处理',
                '模型构建',
                '评价指标',
            ]],
            ['key' => 'results', 'title' => '实验结果与分析', 'ratio' => 0.22, 'subs' => [
                '实验设置',
                '对比实验',
                '消融实验',
                '结果讨论',
            ]],
            ['key' => 'conclusion', 'title' => '结论与展望', 'ratio' => 0.10, 'subs' => [
                '研究结论',
                '研究贡献',
                '研究局限',
                '未来展望',
            ]],
            ['key' => 'references', 'title' => '参考文献', 'ratio' => 0.05],
        ];
    }

    /**
     * 理论研究型模板(人文社科)
     */
    public static function theoretical(): array
    {
        return [
            ['key' => 'abstract', 'title' => '摘要', 'ratio' => 0.03],
            ['key' => 'introduction', 'title' => '引言', 'ratio' => 0.12, 'subs' => [
                '问题提出',
                '研究意义',
                '研究方法与思路',
            ]],
            ['key' => 'literature', 'title' => '文献综述', 'ratio' => 0.22, 'subs' => [
                '核心概念辨析',
                '理论渊源梳理',
                '研究现状评述',
            ]],
            ['key' => 'framework', 'title' => '理论框架', 'ratio' => 0.20, 'subs' => [
                '理论假设',
                '分析框架',
                '核心论点',
            ]],
            ['key' => 'argument', 'title' => '论证展开', 'ratio' => 0.28, 'subs' => [
                '第一层论证',
                '第二层论证',
                '第三层论证',
            ]],
            ['key' => 'conclusion', 'title' => '结论', 'ratio' => 0.10, 'subs' => [
                '研究结论',
                '理论贡献',
                '研究局限',
            ]],
            ['key' => 'references', 'title' => '参考文献', 'ratio' => 0.05],
        ];
    }

    /**
     * 综述型模板
     */
    public static function review(): array
    {
        return [
            ['key' => 'abstract', 'title' => '摘要', 'ratio' => 0.04],
            ['key' => 'introduction', 'title' => '引言', 'ratio' => 0.12, 'subs' => [
                '研究背景',
                '综述范围与方法',
                '综述框架',
            ]],
            ['key' => 'overview', 'title' => '研究概览', 'ratio' => 0.20, 'subs' => [
                '研究历史演进',
                '主要研究流派',
                '研究现状统计',
            ]],
            ['key' => 'analysis', 'title' => '主题分析', 'ratio' => 0.35, 'subs' => [
                '主题一:核心问题',
                '主题二:方法比较',
                '主题三:应用场景',
            ]],
            ['key' => 'future', 'title' => '研究展望', 'ratio' => 0.12, 'subs' => [
                '研究趋势',
                '待解决问题',
                '未来方向',
            ]],
            ['key' => 'conclusion', 'title' => '结论', 'ratio' => 0.08],
            ['key' => 'references', 'title' => '参考文献', 'ratio' => 0.09],
        ];
    }
}

每种模板都包含三个关键信息:章节标题、目标字数比例、建议子标题。 目标字数比例保证了章节的均衡,避免引言写得过长而核心章节一笔带过。

3.2 大纲生成器

大纲生成器结合模板、题目解析结果和 LLM 生成能力,输出完整的大纲。

php
<?php
// app/service/outline/OutlineGenerator.php

namespace app\service\outline;

class OutlineGenerator
{
    /**
     * 生成大纲
     */
    public function generate(array $params): array
    {
        $title = $params['title'];
        $subjectId = $params['subject_id'];
        $wordCount = $params['word_count'] ?? 8000;

        // 1. 获取科目配置
        $subjectService = new SubjectService();
        $subjectConfig = $subjectService->getGenerationConfig($subjectId);

        // 2. 解析题目
        $titleParser = new TitleParser();
        $titleInfo = $titleParser->parse($title, $subjectConfig);

        // 3. 选择模板
        $template = $this->selectTemplate($subjectConfig['discipline_type']);

        // 4. 计算每章目标字数
        $sections = [];
        foreach ($template as $item) {
            $sections[] = [
                'key' => $item['key'],
                'title' => $item['title'],
                'target_words' => (int)round($wordCount * $item['ratio']),
                'subsections' => $item['subs'] ?? [],
            ];
        }

        // 5. 用 LLM 优化子标题
        $sections = $this->refineSubsections($sections, [
            'title' => $title,
            'title_info' => $titleInfo,
            'subject_config' => $subjectConfig,
        ]);

        return [
            'title' => $title,
            'subject_id' => $subjectId,
            'discipline_type' => $subjectConfig['discipline_type'],
            'citation_style' => $subjectConfig['citation_style'],
            'word_count' => $wordCount,
            'title_info' => $titleInfo,
            'sections' => $sections,
        ];
    }

    protected function selectTemplate(string $disciplineType): array
    {
        switch ($disciplineType) {
            case 'theoretical':
                return OutlineTemplates::theoretical();
            case 'review':
                return OutlineTemplates::review();
            case 'empirical':
            default:
                return OutlineTemplates::empirical();
        }
    }

    /**
     * 用 LLM 优化子标题,使其贴合具体题目
     */
    protected function refineSubsections(array $sections, array $context): array
    {
        $titleInfo = $context['title_info'];

        foreach ($sections as &$section) {
            // 摘要和参考文献不需要子标题
            if (in_array($section['key'], ['abstract', 'references'])) {
                continue;
            }

            // 如果模板中没有子标题,让 LLM 生成
            if (empty($section['subsections'])) {
                $section['subsections'] = $this->generateSubsections($section, $context);
            } else {
                // 有子标题,让 LLM 优化使其贴合题目
                $section['subsections'] = $this->optimizeSubsections(
                    $section,
                    $context
                );
            }
        }

        return $sections;
    }

    protected function generateSubsections(array $section, array $context): array
    {
        $title = $context['title'];
        $titleInfo = $context['title_info'];

        $prompt = <<<PROMPT
你是一个学术论文写作助手。请为以下论文的某一章节生成 2-4 个二级子标题。

论文题目:{$title}
研究对象:{$titleInfo['research_object']}
研究方法:{$titleInfo['research_method']}
当前章节:{$section['title']}
该章节目标字数:{$section['target_words']} 字

要求:
1. 子标题应覆盖该章节的核心内容,逻辑递进
2. 子标题应具体明确,避免空泛表述
3. 子标题之间应有清晰的逻辑关系

请以 JSON 格式返回:{"subsections": ["子标题1", "子标题2", ...]}
只返回 JSON。
PROMPT;

        $result = $this->callLLM($prompt);
        return $result['subsections'] ?? [];
    }

    protected function optimizeSubsections(array $section, array $context): array
    {
        // 将通用子标题优化为贴合具体题目的子标题
        // 例如"核心概念界定" → "图像超分辨率重建的核心概念界定"
        return $section['subsections'];
    }

    protected function callLLM(string $prompt): array
    {
        // 实际调用 LLM
        return [];
    }
}

3.3 大纲生成的质量检查

生成的大纲需要经过质量检查,确保结构合理、字数均衡、覆盖完整。

php
<?php
// app/service/outline/OutlineQualityChecker.php

namespace app\service\outline;

class OutlineQualityChecker
{
    public function check(array $outline): array
    {
        $issues = [];

        // 1. 检查章节完整性
        $requiredKeys = ['introduction', 'conclusion', 'references'];
        $keys = array_column($outline['sections'], 'key');
        foreach ($requiredKeys as $key) {
            if (!in_array($key, $keys)) {
                $issues[] = "缺少必要章节:{$key}";
            }
        }

        // 2. 检查字数均衡
        $totalWords = array_sum(array_column($outline['sections'], 'target_words'));
        foreach ($outline['sections'] as $section) {
            $ratio = $section['target_words'] / $totalWords;
            // 核心章节不应低于 8%
            if (!in_array($section['key'], ['abstract', 'references'])
                && $ratio < 0.08) {
                $issues[] = "章节「{$section['title']}」字数占比过低({$ratio})";
            }
        }

        // 3. 检查子标题数量
        foreach ($outline['sections'] as $section) {
            if (in_array($section['key'], ['abstract', 'references'])) {
                continue;
            }
            $subCount = count($section['subsections'] ?? []);
            if ($subCount < 2) {
                $issues[] = "章节「{$section['title']}」子标题过少";
            }
            if ($subCount > 5) {
                $issues[] = "章节「{$section['title']}」子标题过多";
            }
        }

        return [
            'passed' => empty($issues),
            'issues' => $issues,
        ];
    }
}

四、提纲的可编辑性与版本管理

4.1 为什么提纲需要可编辑

生成的大纲不是终点,而是起点。用户需要对大纲进行审查和调整:增删章节、修改子标题、调整字数目标。把 AI 生成的结构暴露给用户审查,而不是让它在黑箱中决定一切。

4.2 大纲的存储

sql
CREATE TABLE `paper_outline` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `paper_id` int(11) NOT NULL,
  `subject_id` int(11) NOT NULL,
  `structure` longtext NOT NULL COMMENT '大纲结构JSON',
  `version` int(11) NOT NULL DEFAULT '1',
  `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0=草稿 1=已确认',
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_paper` (`paper_id`),
  KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

version 字段记录大纲的版本。当用户修改大纲后重新生成正文,系统会保留历史版本。

4.3 版本管理的实现

php
<?php
// app/service/outline/OutlineService.php

namespace app\service\outline;

use think\facade\Db;

class OutlineService
{
    /**
     * 保存大纲(新版本)
     */
    public function save(int $paperId, array $structure): int
    {
        // 获取当前版本号
        $current = Db::name('paper_outline')
            ->where('paper_id', $paperId)
            ->order('version', 'desc')
            ->find();

        $newVersion = $current ? $current['version'] + 1 : 1;

        $id = Db::name('paper_outline')->insertGetId([
            'paper_id' => $paperId,
            'subject_id' => $structure['subject_id'],
            'structure' => json_encode($structure),
            'version' => $newVersion,
            'status' => 0,
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        return $id;
    }

    /**
     * 确认大纲
     */
    public function confirm(int $outlineId): bool
    {
        Db::name('paper_outline')
            ->where('id', $outlineId)
            ->update([
                'status' => 1,
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
        return true;
    }

    /**
     * 获取指定版本
     */
    public function getVersion(int $paperId, int $version): ?array
    {
        $outline = Db::name('paper_outline')
            ->where('paper_id', $paperId)
            ->where('version', $version)
            ->find();

        if (!$outline) return null;

        return json_decode($outline['structure'], true);
    }

    /**
     * 回滚到指定版本
     */
    public function rollback(int $paperId, int $version): int
    {
        $structure = $this->getVersion($paperId, $version);
        if (!$structure) {
            throw new \Exception('版本不存在');
        }

        return $this->save($paperId, $structure);
    }
}

版本管理的价值在于可回溯。 如果用户修改大纲后生成的正文不满意,可以回滚到之前的版本重新生成,而不需要从头开始。

五、从大纲到正文的衔接

5.1 大纲作为生成的约束

大纲确认后,系统按章节逐个生成正文。每个章节的生成都受大纲约束:章节标题、子标题、目标字数。

php
<?php
// app/service/generator/PaperGenerator.php

namespace app\service\generator;

use think\facade\Db;
use think\facade\Queue;

class PaperGenerator
{
    /**
     * 提交生成任务
     */
    public function submit(int $paperId, int $outlineId): string
    {
        $outline = Db::name('paper_outline')->where('id', $outlineId)->find();
        if (!$outline) {
            throw new \Exception('大纲不存在');
        }

        if ($outline['status'] != 1) {
            throw new \Exception('大纲未确认');
        }

        $taskNo = date('YmdHis') . mt_rand(1000, 9999);

        Db::name('paper')->where('id', $paperId)->update([
            'outline_id' => $outlineId,
            'status' => 'generating',
            'task_no' => $taskNo,
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        Queue::push('app\job\GeneratePaper', [
            'paper_id' => $paperId,
            'outline_id' => $outlineId,
        ], 'paper');

        return $taskNo;
    }
}

5.2 分章生成与上下文传递

分章生成的核心是上下文摘要传递:每生成完一章,生成该章的摘要,作为下一章生成的上下文。

php
<?php
// app/job/GeneratePaper.php

namespace app\job;

use think\queue\Job;
use app\service\generator\SectionGenerator;
use app\service\generator\AbstractGenerator;

class GeneratePaper
{
    public function fire(Job $job, $data)
    {
        $paperId = $data['paper_id'];
        $outlineId = $data['outline_id'];

        try {
            $outline = \think\facade\Db::name('paper_outline')
                ->where('id', $outlineId)
                ->find();
            $structure = json_decode($outline['structure'], true);

            $generator = new SectionGenerator();
            $context = ['generated' => [], 'references' => []];

            $sections = $structure['sections'];
            $total = count($sections);
            $results = [];

            foreach ($sections as $index => $section) {
                // 跳过摘要和参考文献(最后生成)
                if (in_array($section['key'], ['abstract', 'references'])) {
                    continue;
                }

                $progress = (int)(80 * $index / $total);
                $this->updateProgress($paperId, $progress, "生成:{$section['title']}");

                $content = $generator->generate($section, $context, $structure);
                $results[$section['key']] = $content;

                // 生成摘要供后续章节使用
                $context['generated'][$section['key']] = [
                    'title' => $section['title'],
                    'summary' => $generator->summarize($content),
                ];
            }

            // 生成摘要
            $this->updateProgress($paperId, 85, '生成摘要');
            $abstractGenerator = new AbstractGenerator();
            $results['abstract'] = $abstractGenerator->generate($structure, $results);

            // 生成参考文献
            $this->updateProgress($paperId, 90, '整理参考文献');
            $results['references'] = $generator->formatReferences($context['references']);

            // 保存全文
            $this->updateProgress($paperId, 95, '保存');
            $fullText = $this->assemble($structure, $results);
            \think\facade\Db::name('paper')->where('id', $paperId)->update([
                'content' => $fullText,
                'status' => 'completed',
                'completed_at' => date('Y-m-d H:i:s'),
            ]);

            $this->updateProgress($paperId, 100, '完成');
            $job->delete();

        } catch (\Exception $e) {
            \think\facade\Log::error('论文生成失败', [
                'paper_id' => $paperId,
                'error' => $e->getMessage(),
            ]);
            \think\facade\Db::name('paper')->where('id', $paperId)->update([
                'status' => 'failed',
                'error' => $e->getMessage(),
            ]);
            $job->delete();
        }
    }

    protected function assemble(array $structure, array $results): string
    {
        $parts = [];
        foreach ($structure['sections'] as $section) {
            if (isset($results[$section['key']])) {
                $parts[] = "## {$section['title']}\n\n" . $results[$section['key']];
            }
        }
        return implode("\n\n", $parts);
    }

    protected function updateProgress(int $paperId, int $progress, string $message): void
    {
        \think\facade\Cache::set(
            "paper:progress:{$paperId}",
            ['progress' => $progress, 'message' => $message],
            3600
        );
    }
}

六、边界与张力

论文大师系统在工程实践中,有几个需要清醒认识的边界。

第一,学科差异的适配难度。 理工科论文有实验数据、公式推导、图表规范;人文社科论文有理论辨析、文本解读、论证逻辑。一套通用的模板很难覆盖所有学科。系统需要为不同学科提供差异化的模板和生成策略,且需要领域专家的参与来设计模板。

第二,大纲生成的"正确性"问题。 生成的大纲在结构上可能是合理的,但在学术上可能不够专业。例如,对于某个具体的研究问题,合适的章节划分可能与通用模板差异很大。LLM 可以优化子标题,但无法保证大纲的学术严谨性。

第三,引用管理的根本风险。 AI 生成论文的一个常见问题是虚构引用。系统需要将引用与生成分离,从真实文献库中检索匹配的文献,而不是让 LLM 自由生成引用。

第四,用户的过度依赖。 如果系统让用户觉得"大纲不用自己想",可能导致用户缺乏对论文结构的深度思考。系统的定位应该是"辅助"而非"代写",在产品层面需要明确这一点。

第五,查重与 AI 检测的对抗。 高校和期刊正在加强对 AI 生成内容的检测。系统需要提供查重预检和 AI 痕迹优化功能,但这也可能引导系统走向"规避检测"而非"提升质量"的错误方向。

结语:提纲生成是学术写作的"结构工程"

论文大师源码的核心工程判断,可以归结为一句话:论文写作的瓶颈不在文字生成,而在结构设计。

科目选择决定了学术范式,题目解析提取了研究对象和方法,大纲生成器结合模板和 LLM 产出结构化的提纲。这套流程的价值在于:它把"论文应该长什么样"这个结构性问题,从用户的脑海中转移到了系统的工程流程中。

最新回复 (0)

    暂无评论

请先登录后发表评论!

返回
请先登录后发表评论!