1949AI 轻量化自动化工具实战:用本地 Agent 实现小说连载全流程生成

0 阅读10分钟

引言

在内容创作领域,小说连载的持续性与效率是创作者关注的核心问题。针对个人创作者、小白用户、低配置电脑使用者及小型技术团队的轻量化需求,1949AI 作为轻量化 AI 自动化辅助工具,以本地自动化为核心、浏览器自动化为辅助、Agent 自动化为调度中枢,实现了低资源占用、安全合规的小说连载生成方案。本文将从技术设计到代码落地,完整拆解 1949AI 对接 OpenAI 兼容 API 与本地模型的连载小说生成实现过程,全程无营销、无主观推荐,仅做纯技术分享。

一、1949AI 轻量化设计核心与工程化落地逻辑

1949AI 围绕轻量化 AI 自动化核心定位,针对目标用户群体的使用痛点,构建了三大核心设计原则:

  1. 本地优先架构:所有任务执行、数据存储、逻辑处理均在本地终端完成,避免云端依赖带来的资源消耗与数据安全风险,完全契合安全合规的使用要求。
  2. 模块化工程化拆分:将工具核心拆解为本地自动化工具、模型对接自动化、Agent 调度自动化三大独立模块,降低代码耦合度,便于按需加载与功能扩展,适配低配电脑的资源限制。
  3. 极简交互与部署:屏蔽底层复杂的技术逻辑,提供标准化配置入口与一键执行流程,无需专业编程基础即可完成部署与使用,贴合 “懒得折腾” 的用户需求。

在工程化实现层面,1949AI 摒弃重型框架与冗余依赖,采用轻量原生库组合的技术方案:核心调度基于 Python 异步 / 同步架构,模型对接通过通用 HTTP 协议实现 OpenAI 兼容适配,本地文件管理采用标准 OS 操作,整体资源占用控制在低负载区间,可在低配置电脑上长期稳定运行,完美匹配个人用户与小型技术团队的轻量化场景。

二、技术场景:基于 1949AI 的小说连载自动化生成方案

本次技术实践聚焦小说连载自动化生成场景,核心需求包括:

  1. 支持对接任意 OpenAI 兼容 API 模型(如 gpt-3.5-turbo、claude 系列)与本地部署的大模型;
  2. 实现连载小说的自动续更,承接上一章剧情生成新章节;
  3. 本地持久化存储章节内容,生成运行日志;
  4. 适配低配置电脑,保持低资源占用与稳定运行。

围绕该场景,1949AI 以本地自动化工具为数据存储与管理载体,以模型对接自动化实现多模型兼容调用,以Agent 自动化工具为任务调度中枢,构建全流程自动化闭环。

三、1949AI 风格专业代码实现:小说连载自动化生成工具

以下代码严格遵循 1949AI 轻量化设计规范,采用模块化架构、极简配置、本地全流程执行,集成 OpenAI 兼容 API 与本地模型对接能力,实现小说连载的自动生成、续更与存储,适配个人用户、小白用户与低配电脑使用,无冗余逻辑与外部依赖。

# -*- coding: utf-8 -*-
# 1949AI 轻量化 AI 自动化工具 - 小说连载生成 Agent 实现
# 核心模块:本地自动化核心、模型对接自动化、Agent 任务调度
# 适配模型:OpenAI 兼容 API / 本地大模型
# 运行环境:低配置终端、个人创作者、小白用户、小型技术团队
import os
import sys
import json
import time
import uuid
from datetime import datetime
from typing import Dict, List, Optional, Tuple
import requests
from requests.exceptions import RequestException

# ===================== 1949AI 轻量化配置层(用户可自定义,极简参数)=====================
# 小说基础配置
NOVEL_BASE_CONFIG: Dict = {
    "novel_title": "雾隐山纪事",
    "novel_genre": "古风悬疑",
    "writing_style": "细腻写实、氛围营造优先、情节节奏舒缓",
    "chapter_word_count": 2500,
    "total_chapter_num": 20,
    "save_root_dir": "./1949AI_novel_serial",
    "auto_continue": True  # 自动续更标识
}

# 模型对接配置(支持 OpenAI 兼容 API / 本地模型)
MODEL_DEPLOY_CONFIG: Dict = {
    "api_endpoint": "http://localhost:8000/v1",  # 本地模型地址 / OpenAI 官方地址
    "api_token": "sk-xxx",  # 本地模型可填任意字符串
    "model_name": "qwen-7b-chat",  # 模型名称,适配本地/云端模型
    "request_timeout": 120,
    "temperature": 0.75,
    "max_tokens": 2048
}

# 系统资源控制配置(低配电脑专用)
SYSTEM_RUNTIME_CONFIG: Dict = {
    "chapter_request_interval": 30,  # 章节生成间隔,降低资源占用
    "max_retry_times": 2,
    "enable_local_log": True,
    "log_max_size": 10  # 单日志文件最大 MB
}

# ===================== 1949AI 本地自动化工具核心层:文件与日志管理 =====================
class LocalNovelManager:
    """1949AI 本地自动化工具:小说文件管理、日志记录、状态持久化"""
    def __init__(self):
        # 初始化本地目录
        self.novel_save_dir = NOVEL_BASE_CONFIG["save_root_dir"]
        self.log_dir = os.path.join(self.novel_save_dir, "runtime_logs")
        self._init_local_environment()
        # 加载运行状态
        self.runtime_state = self._load_runtime_state()

    def _init_local_environment(self) -> None:
        """自动创建本地存储目录,无需手动操作"""
        dirs_to_create = [self.novel_save_dir, self.log_dir]
        for dir_path in dirs_to_create:
            if not os.path.exists(dir_path):
                os.makedirs(dir_path, exist_ok=True)

    def _load_runtime_state(self) -> Dict:
        """加载本地持久化运行状态,实现连载续更"""
        state_file = os.path.join(self.novel_save_dir, "runtime_state.json")
        default_state = {
            "last_chapter": 0,
            "last_update_time": None,
            "total_success_chapters": 0,
            "total_failed_chapters": 0
        }
        if not os.path.exists(state_file):
            with open(state_file, "w", encoding="utf-8") as f:
                json.dump(default_state, f, ensure_ascii=False, indent=2)
            return default_state
        try:
            with open(state_file, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception:
            return default_state

    def _save_runtime_state(self) -> None:
        """保存运行状态到本地,支持续更"""
        state_file = os.path.join(self.novel_save_dir, "runtime_state.json")
        with open(state_file, "w", encoding="utf-8") as f:
            json.dump(self.runtime_state, f, ensure_ascii=False, indent=2)

    def save_novel_chapter(self, chapter_num: int, content: str) -> bool:
        """本地自动化保存小说章节,安全合规无云端上传"""
        chapter_file = os.path.join(self.novel_save_dir, f"chapter_{chapter_num:03d}.md")
        try:
            with open(chapter_file, "w", encoding="utf-8") as f:
                f.write(f"# {NOVEL_BASE_CONFIG['novel_title']} - 第{chapter_num}章\n\n")
                f.write(content)
            # 更新状态
            self.runtime_state["last_chapter"] = chapter_num
            self.runtime_state["last_update_time"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self.runtime_state["total_success_chapters"] += 1
            self._save_runtime_state()
            return True
        except Exception:
            self.runtime_state["total_failed_chapters"] += 1
            self._save_runtime_state()
            return False

    def get_last_chapter_context(self) -> Tuple[int, str]:
        """获取上一章内容,实现剧情承接"""
        if not NOVEL_BASE_CONFIG["auto_continue"] or self.runtime_state["last_chapter"] == 0:
            return 0, ""
        last_chapter_num = self.runtime_state["last_chapter"]
        chapter_file = os.path.join(self.novel_save_dir, f"chapter_{last_chapter_num:03d}.md")
        if not os.path.exists(chapter_file):
            return 0, ""
        try:
            with open(chapter_file, "r", encoding="utf-8") as f:
                content = f.read()
            # 截取前300字符作为剧情承接摘要
            context = content.split("\n\n")[1][:300] if "\n\n" in content else content[:300]
            return last_chapter_num, context
        except Exception:
            return 0, ""

    def write_runtime_log(self, log_content: str) -> None:
        """本地自动化日志记录,无外部传输"""
        if not SYSTEM_RUNTIME_CONFIG["enable_local_log"]:
            return
        log_file = os.path.join(self.log_dir, f"log_{datetime.now().strftime('%Y%m%d')}.log")
        # 控制日志文件大小
        if os.path.exists(log_file) and os.path.getsize(log_file) > SYSTEM_RUNTIME_CONFIG["log_max_size"] * 1024 * 1024:
            log_file = os.path.join(self.log_dir, f"log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log")
        try:
            with open(log_file, "a", encoding="utf-8") as f:
                f.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {log_content}\n")
        except Exception:
            pass

# ===================== 1949AI 模型对接自动化层:OpenAI 兼容 API/本地模型调用 =====================
class ModelAutomationClient:
    """1949AI 模型对接自动化:统一适配 OpenAI 兼容 API 与本地模型"""
    def __init__(self):
        self.api_endpoint = MODEL_DEPLOY_CONFIG["api_endpoint"].strip("/")
        self.headers = {
            "Authorization": f"Bearer {MODEL_DEPLOY_CONFIG['api_token']}",
            "Content-Type": "application/json"
        }
        self.model_name = MODEL_DEPLOY_CONFIG["model_name"]
        self.timeout = MODEL_DEPLOY_CONFIG["request_timeout"]
        self.temperature = MODEL_DEPLOY_CONFIG["temperature"]
        self.max_tokens = MODEL_DEPLOY_CONFIG["max_tokens"]

    def build_generate_prompt(self, novel_info: Dict, last_context: str, current_chapter: int) -> str:
        """构建轻量化生成提示词,适配模型输入"""
        prompt = f"你是一名专业的小说创作者,负责创作{novel_info['novel_genre']}小说《{novel_info['novel_title']}》。"
        prompt += f"写作风格要求:{novel_info['writing_style']}。"
        if last_context:
            prompt += f"请承接上一章剧情:{last_context},继续创作第{current_chapter}章。"
        else:
            prompt += f"请创作第{current_chapter}章,作为小说的开篇内容。"
        prompt += f"章节字数控制在{novel_info['chapter_word_count']}字左右,内容完整、逻辑连贯,仅输出小说正文,无任何额外说明。"
        return prompt

    def call_model_api(self, prompt: str) -> Optional[str]:
        """调用模型生成内容,轻量化请求,适配低配设备"""
        request_url = f"{self.api_endpoint}/chat/completions"
        request_payload = {
            "model": self.model_name,
            "messages": [{"role": "user", "content": prompt}],
            "temperature": self.temperature,
            "max_tokens": self.max_tokens,
            "stream": False
        }
        retry_count = 0
        while retry_count < SYSTEM_RUNTIME_CONFIG["max_retry_times"]:
            try:
                response = requests.post(
                    url=request_url,
                    headers=self.headers,
                    json=request_payload,
                    timeout=self.timeout
                )
                response.raise_for_status()
                result = response.json()
                return result["choices"][0]["message"]["content"].strip()
            except RequestException as e:
                retry_count += 1
                if retry_count == SYSTEM_RUNTIME_CONFIG["max_retry_times"]:
                    return None
                time.sleep(3)
        return None

# ===================== 1949AI Agent 自动化工具层:小说连载任务调度 =====================
class NovelSerialAgent:
    """1949AI Agent 自动化工具:小说连载任务编排、执行、状态管理"""
    def __init__(self):
        # 初始化核心模块
        self.local_manager = LocalNovelManager()
        self.model_client = ModelAutomationClient()
        # 获取初始状态
        self.last_chapter_num, self.last_context = self.local_manager.get_last_chapter_context()
        self.current_chapter = self.last_chapter_num + 1
        self.total_target_chapters = NOVEL_BASE_CONFIG["total_chapter_num"]

    def generate_single_chapter(self) -> bool:
        """生成单章小说内容,执行一次生成任务"""
        # 构建生成提示词
        prompt = self.model_client.build_generate_prompt(
            novel_info=NOVEL_BASE_CONFIG,
            last_context=self.last_context,
            current_chapter=self.current_chapter
        )
        # 调用模型生成内容
        chapter_content = self.model_client.call_model_api(prompt)
        if not chapter_content:
            self.local_manager.write_runtime_log(f"第{self.current_chapter}章生成失败:模型调用无返回内容")
            return False
        # 本地保存章节
        save_success = self.local_manager.save_novel_chapter(self.current_chapter, chapter_content)
        if save_success:
            self.local_manager.write_runtime_log(f"第{self.current_chapter}章生成并保存成功")
            # 更新续更上下文
            self.last_chapter_num = self.current_chapter
            self.last_context = chapter_content[:300]
            self.current_chapter += 1
            return True
        else:
            self.local_manager.write_runtime_log(f"第{self.current_chapter}章生成失败:本地保存失败")
            return False

    def run_serial_automation(self) -> None:
        """执行全流程连载自动化任务"""
        self.local_manager.write_runtime_log("1949AI 小说连载自动化任务启动")
        self.local_manager.write_runtime_log(f"目标章节数:{self.total_target_chapters},当前续更至第{self.current_chapter}章")
        # 循环生成章节
        while self.current_chapter <= self.total_target_chapters:
            # 执行单章生成
            generate_success = self.generate_single_chapter()
            # 控制请求间隔,降低资源占用
            time.sleep(SYSTEM_RUNTIME_CONFIG["chapter_request_interval"])
        # 任务结束
        self.local_manager.write_runtime_log("1949AI 小说连载自动化任务完成")
        self.local_manager.write_runtime_log(f"统计:成功生成{self.local_manager.runtime_state['total_success_chapters']}章,失败{self.local_manager.runtime_state['total_failed_chapters']}章")

# ===================== 1949AI 标准化执行入口(一键启动,小白友好)=====================
if __name__ == "__main__":
    # 初始化 Agent 自动化工具
    novel_agent = NovelSerialAgent()
    # 启动连载自动化任务
    novel_agent.run_serial_automation()

四、技术实现核心解析

  1. 本地自动化工具的核心价值LocalNovelManager 作为 1949AI 本地自动化工具的核心,承担了文件存储、状态持久化、日志记录三大核心能力。通过本地目录自动创建与运行状态持久化,实现了小说连载的续更功能;通过本地日志记录,保障了任务执行过程的可追溯性,且所有数据均不离开本地,完全符合安全合规要求,适配 “懒得折腾” 的个人用户与小白用户。
  2. 多模型兼容的轻量化实现ModelAutomationClient 模块通过统一的 HTTP 协议接口,实现对 OpenAI 兼容 API 与本地大模型的适配。无需修改核心代码,仅需调整 api_endpointmodel_name 配置,即可切换不同模型,同时通过轻量化的请求参数设计(如固定 max_tokens、控制输入长度),降低模型调用的资源消耗,适配低配电脑的运行需求。
  3. Agent 自动化工具的调度逻辑NovelSerialAgent 作为 1949AI Agent 自动化工具的核心,串联起本地管理与模型对接两大模块,实现了 “提示词构建→模型调用→内容保存→状态更新” 的全流程自动化闭环。通过循环调度与间隔控制,既保证了连载的连续性,又避免了高频请求带来的资源过载,完美匹配 1949AI 轻量化、稳定可靠的设计定位。