修复scriptAgent工具,并添加ctx上下文

This commit is contained in:
ACT丶流星雨 2026-03-23 21:10:03 +08:00
parent 651c60570d
commit ec57055bd4
6 changed files with 56 additions and 42 deletions

View File

@ -29,6 +29,7 @@ description: >-
| 集数 | 总共拆分为几集 | 7集 | | 集数 | 总共拆分为几集 | 7集 |
| 单集时长 | 每集目标时长(分钟) | 2.5分钟 | | 单集时长 | 每集目标时长(分钟) | 2.5分钟 |
| 原著范围 | 改编覆盖的章节范围 | 第1-35章 | | 原著范围 | 改编覆盖的章节范围 | 第1-35章 |
| 章节ID列表 | 本次任务涉及的章节ID用于事件检索 | [1,2,3,4,5] |
| 平台规格 | 画面比例(竖屏/横屏) | 竖屏9:16 | | 平台规格 | 画面比例(竖屏/横屏) | 竖屏9:16 |
| 风格定位 | 短剧整体风格标签 | 诡异修仙+心理悬疑 | | 风格定位 | 短剧整体风格标签 | 诡异修仙+心理悬疑 |
| 付费策略 | 前几集免费、从第几集设付费点 | 前2集免费第3集起付费 | | 付费策略 | 前几集免费、从第几集设付费点 | 前2集免费第3集起付费 |
@ -50,6 +51,7 @@ description: >-
- 集数:{totalEpisodes}集 - 集数:{totalEpisodes}集
- 单集时长:{episodeDuration}分钟(约{wordsPerEpisode}字台词) - 单集时长:{episodeDuration}分钟(约{wordsPerEpisode}字台词)
- 原著范围:第{startChapter}-{endChapter}章 - 原著范围:第{startChapter}-{endChapter}章
- 章节ID列表{chapterIds}
- 平台规格:{platform} - 平台规格:{platform}
- 风格定位:{style} - 风格定位:{style}
- 付费策略:{paywall} - 付费策略:{paywall}
@ -72,24 +74,24 @@ description: >-
### 阶段1事件提取Event Extraction ### 阶段1事件提取Event Extraction
- **触发词**提取事件、分析章节、事件列表、event - **触发词**提取事件、分析章节、事件列表、event
- **输入**原著小说章节文本 - **输入**章节ID列表由系统提示词中的章节映射表解析
- **输出**:结构化事件表(章节、角色、核心事件、主线关系、信息点数、预估时长、情绪强度) - **输出**:结构化事件表(章节、角色、核心事件、主线关系、信息点数、预估时长、情绪强度)
- **派发指令模板** - **派发指令模板**
``` ```
你是执行层Agent请执行【事件提取】任务。 你是执行层Agent请执行【事件提取】任务。
目标:从原著第{start}章到第{end}章提取结构化事件表。 目标:基于章节ID获取结构化事件表。
要求: 要求:
1. 调用 get_novel_text 获取原著文本 1. 按系统提示词中的章节映射表确定章节ID数组 ids:number[]
2. 按事件提取规范逐章分析 2. 调用 get_novel_events 获取事件数据(传入 ids:number[]
3. 输出标准事件表格式 3. 按事件提取规范整理为标准事件表格式
4. 调用 set_planData_event 保存结果 4. 将事件表作为后续阶段上下文返回(不写入 planData
``` ```
### 阶段2故事骨架Story Skeleton ### 阶段2故事骨架Story Skeleton
- **触发词**故事骨架、分集、三幕结构、skeleton - **触发词**故事骨架、分集、三幕结构、skeleton
- **输入**:事件表(阶段1产出 - **输入**:事件表(通过 get_novel_events 获取
- **输出**:三幕结构 + 分集决策 + 全局删减记录 + 付费卡点设计 - **输出**:三幕结构 + 分集决策 + 全局删减记录 + 付费卡点设计
- **前置条件**:事件表已完成 - **前置条件**:事件表已完成
- **派发指令模板** - **派发指令模板**
@ -98,7 +100,7 @@ description: >-
你是执行层Agent请执行【故事骨架搭建】任务。 你是执行层Agent请执行【故事骨架搭建】任务。
目标:基于已有事件表构建故事骨架。 目标:基于已有事件表构建故事骨架。
要求: 要求:
1. 调用 get_planData 获取当前事件表 1. 调用 get_novel_events 获取当前任务章节的事件表(传入 ids:number[]
2. 设计三幕结构,明确每幕功能、核心问题、幕末转折 2. 设计三幕结构,明确每幕功能、核心问题、幕末转折
3. 制定分集决策({totalEpisodes}集×{episodeDuration}分钟),每集包含戏剧功能、核心场景、章节分配、删减决策、集末钩子、付费点 3. 制定分集决策({totalEpisodes}集×{episodeDuration}分钟),每集包含戏剧功能、核心场景、章节分配、删减决策、集末钩子、付费点
4. 记录全局删减决策 4. 记录全局删减决策
@ -108,7 +110,7 @@ description: >-
### 阶段3改编策略Adaptation Strategy ### 阶段3改编策略Adaptation Strategy
- **触发词**改编策略、改编决策、改编原则、adaptation - **触发词**改编策略、改编决策、改编原则、adaptation
- **输入**:事件表 + 故事骨架(阶段1-2产出 - **输入**:事件表(通过 get_novel_events 获取) + 故事骨架阶段2产出
- **输出**:核心改编原则 + 删除决策 + 世界观呈现策略 - **输出**:核心改编原则 + 删除决策 + 世界观呈现策略
- **前置条件**:故事骨架已完成 - **前置条件**:故事骨架已完成
- **派发指令模板** - **派发指令模板**
@ -117,7 +119,7 @@ description: >-
你是执行层Agent请执行【改编策略制定】任务。 你是执行层Agent请执行【改编策略制定】任务。
目标:基于事件表和故事骨架制定改编策略。 目标:基于事件表和故事骨架制定改编策略。
要求: 要求:
1. 调用 get_planData 获取事件表和故事骨架 1. 调用 get_novel_events 获取事件表(传入 ids:number[]),并调用 get_planData 获取故事骨架
2. 确立核心改编原则(故事核优先、双线剪辑策略、恐怖克制原则) 2. 确立核心改编原则(故事核优先、双线剪辑策略、恐怖克制原则)
3. 列出主要删除决策及理由 3. 列出主要删除决策及理由
4. 制定世界观呈现策略 4. 制定世界观呈现策略
@ -127,7 +129,7 @@ description: >-
### 阶段4剧本编写Script Writing ### 阶段4剧本编写Script Writing
- **触发词**写剧本、编剧、分镜脚本、script - **触发词**写剧本、编剧、分镜脚本、script
- **输入**:事件表 + 故事骨架 + 改编策略阶段1-3产出 - **输入**:事件表(通过 get_novel_events 获取) + 故事骨架 + 改编策略阶段2-3产出
- **输出**:分集剧本(节拍结构 + 分镜脚本) - **输出**:分集剧本(节拍结构 + 分镜脚本)
- **前置条件**:改编策略已完成 - **前置条件**:改编策略已完成
- **派发指令模板** - **派发指令模板**
@ -137,7 +139,7 @@ description: >-
目标:编写第{ep}集剧本。 目标:编写第{ep}集剧本。
集信息:{从骨架获取的该集信息} 集信息:{从骨架获取的该集信息}
要求: 要求:
1. 调用 get_planData 获取全部工作区数据 1. 调用 get_novel_events 获取该集对应章节事件(传入 ids:number[]),并调用 get_planData 获取故事骨架与改编策略
2. 按节拍结构编写,严格控制总时长在{episodeDuration}分钟(约{wordsPerEpisode}字台词) 2. 按节拍结构编写,严格控制总时长在{episodeDuration}分钟(约{wordsPerEpisode}字台词)
3. 每个节拍包含:场景描述、画面描述、台词、内心独白 3. 每个节拍包含:场景描述、画面描述、台词、内心独白
4. 竖屏9:16格式注意画面构图适配 4. 竖屏9:16格式注意画面构图适配

View File

@ -18,17 +18,17 @@
### 阶段1事件提取 ### 阶段1事件提取
``` ```
输入:原著小说文本第1-35章 输入:章节ID数组 ids:number[](由系统提示词中的章节映射表提供
处理:逐章提取结构化事件 处理:调用事件检索工具并整理为标准事件表
输出:planData.eventMarkdown事件表 输出:事件表Markdown作为后续阶段上下文不写入 planData
工具get_novel_text → set_planData_event 工具get_novel_events(ids:number[])
质量门章节覆盖率100%、角色名统一、强主线≥20章 质量门章节覆盖率100%、角色名统一、强主线≥20章
``` ```
### 阶段2故事骨架 ### 阶段2故事骨架
``` ```
输入:planData.event 输入:事件表(通过 get_novel_events(ids:number[]) 获取)
处理:三幕分割、按项目配置分集、删减决策、钩子设计 处理:三幕分割、按项目配置分集、删减决策、钩子设计
输出planData.storySkeleton 输出planData.storySkeleton
工具get_planData → set_planData_storySkeleton 工具get_planData → set_planData_storySkeleton
@ -39,7 +39,7 @@
### 阶段3改编策略 ### 阶段3改编策略
``` ```
输入:planData.event + planData.storySkeleton 输入:事件表get_novel_events + planData.storySkeleton
处理:提炼改编原则、确定删减依据、世界观呈现策略 处理:提炼改编原则、确定删减依据、世界观呈现策略
输出planData.adaptationStrategy 输出planData.adaptationStrategy
工具get_planData → set_planData_adaptationStrategy 工具get_planData → set_planData_adaptationStrategy
@ -50,10 +50,10 @@
### 阶段4剧本编写 ### 阶段4剧本编写
``` ```
输入:planData.event + planData.storySkeleton + planData.adaptationStrategy 输入:事件表get_novel_events + planData.storySkeleton + planData.adaptationStrategy
处理:按集编写(可并行或逐集) 处理:按集编写(可并行或逐集)
输出planData.script 输出planData.script
工具get_planData + get_novel_text → set_planData_script 工具get_novel_events + get_planData + get_novel_text → set_planData_script
质量门:时长合规、台词字数、画面可执行、资产一致 质量门:时长合规、台词字数、画面可执行、资产一致
前置条件阶段3通过审核 前置条件阶段3通过审核
``` ```

View File

@ -3,7 +3,7 @@ name: execution
description: >- description: >-
短剧改编执行层Agent技能。负责接收决策层派发的具体任务并执行涵盖事件提取、 短剧改编执行层Agent技能。负责接收决策层派发的具体任务并执行涵盖事件提取、
故事骨架搭建、改编策略制定、剧本编写四大任务类型。使用 get_novel_text 读取原著, 故事骨架搭建、改编策略制定、剧本编写四大任务类型。使用 get_novel_text 读取原著,
使用 get_planData 获取工作区状态,使用 set_planData 系列工具保存产出物。 使用 get_novel_events 获取章节事件数据,使用 get_planData 获取工作区状态,使用 set_planData 系列工具保存产出物。
当收到决策层的 run_sub_agent 调用时激活。 当收到决策层的 run_sub_agent 调用时激活。
--- ---
@ -16,7 +16,6 @@ description: >-
```typescript ```typescript
const planData = { const planData = {
event: string, // 章节事件表
storySkeleton: string, // 故事骨架 storySkeleton: string, // 故事骨架
adaptationStrategy: string, // 改编策略 adaptationStrategy: string, // 改编策略
script: string, // 剧本内容 script: string, // 剧本内容
@ -24,7 +23,8 @@ const planData = {
``` ```
- 读取:`get_planData` → 返回完整 planData 对象 - 读取:`get_planData` → 返回完整 planData 对象
- 写入:`set_planData_event` / `set_planData_storySkeleton` / `set_planData_adaptationStrategy` / `set_planData_script` - 事件读取:`get_novel_events(ids:number[])` → 返回指定章节ID的事件数据
- 写入:`set_planData_storySkeleton` / `set_planData_adaptationStrategy` / `set_planData_script`
## 项目背景 ## 项目背景
@ -52,7 +52,8 @@ const planData = {
**执行流程** **执行流程**
1. 调用 `get_novel_text` 获取指定章节范围的原著文本 1. 根据决策层传入的章节ID构建 `ids:number[]`
2. 调用 `get_novel_events(ids:number[])` 获取结构化事件数据
2. 逐章分析,提取以下维度: 2. 逐章分析,提取以下维度:
| 字段 | 说明 | 示例 | | 字段 | 说明 | 示例 |
@ -66,7 +67,7 @@ const planData = {
| 情绪强度 | 情绪标签 | 冲突+恐怖 | | 情绪强度 | 情绪标签 | 冲突+恐怖 |
3. 生成汇总统计(总章节、强主线章节数、可压缩章节、预估总时长、目标时长、压缩比) 3. 生成汇总统计(总章节、强主线章节数、可压缩章节、预估总时长、目标时长、压缩比)
4. 调用 `set_planData_event` 保存 Markdown 表格格式的事件表 4. 输出 Markdown 表格格式的事件表,作为后续任务上下文(不写入 planData
**输出格式**:参考 [event-format.md](references/event-format.md) **输出格式**:参考 [event-format.md](references/event-format.md)
@ -83,7 +84,7 @@ const planData = {
**执行流程** **执行流程**
1. 调用 `get_planData` 获取已有事件表 1. 调用 `get_novel_events(ids:number[])` 获取已有事件表
2. 确定故事核(一句话总结整部剧的核心吸引力) 2. 确定故事核(一句话总结整部剧的核心吸引力)
3. 提炼隐线(人物弧:主角的内在成长轨迹) 3. 提炼隐线(人物弧:主角的内在成长轨迹)
4. 设计三幕结构: 4. 设计三幕结构:
@ -122,7 +123,7 @@ const planData = {
**执行流程** **执行流程**
1. 调用 `get_planData` 获取事件表和故事骨架 1. 调用 `get_novel_events(ids:number[])` 获取事件表,并调用 `get_planData` 获取故事骨架
2. 制定核心改编原则3-5条每条原则必须 2. 制定核心改编原则3-5条每条原则必须
- 明确优先级 - 明确优先级
- 给出正面指导("应该做什么")和负面边界("不应该做什么" - 给出正面指导("应该做什么")和负面边界("不应该做什么"
@ -152,7 +153,7 @@ const planData = {
**执行流程** **执行流程**
1. 调用 `get_planData` 获取全部工作区数据(事件表、骨架、改编策略) 1. 调用 `get_novel_events(ids:number[])` 获取事件表,并调用 `get_planData` 获取骨架与改编策略
2. 根据指定集数,从骨架中获取该集的: 2. 根据指定集数,从骨架中获取该集的:
- 覆盖章节范围 - 覆盖章节范围
- 戏剧功能 - 戏剧功能
@ -181,7 +182,7 @@ const planData = {
## 通用执行规范 ## 通用执行规范
1. **先读后写**:执行任何任务前,先调用 `get_planData` 了解当前工作区状态 1. **先读后写**:执行任何任务前,先调用 `get_planData` 了解工作区状态,并按需调用 `get_novel_events(ids:number[])` 获取事件数据
2. **增量更新**:如果工作区已有内容,在其基础上修改而非全部覆盖(除非指令明确要求重写) 2. **增量更新**:如果工作区已有内容,在其基础上修改而非全部覆盖(除非指令明确要求重写)
3. **格式一致**:严格按照对应的输出格式规范,使用 Markdown 格式 3. **格式一致**:严格按照对应的输出格式规范,使用 Markdown 格式
4. **任务边界**:只执行指令中明确要求的任务,不越权执行其他阶段 4. **任务边界**:只执行指令中明确要求的任务,不越权执行其他阶段

View File

@ -1,10 +1,10 @@
import { tool, Tool } from "ai"; import { tool, Tool } from "ai";
import u from "@/utils";
import { z } from "zod"; import { z } from "zod";
import _ from "lodash"; import _ from "lodash";
import ResTool from "@/socket/resTool"; import ResTool from "@/socket/resTool";
export const planData = z.object({ export const planData = z.object({
event: z.string().describe("章节事件"),
storySkeleton: z.string().describe("故事骨架"), storySkeleton: z.string().describe("故事骨架"),
adaptationStrategy: z.string().describe("改编策略"), adaptationStrategy: z.string().describe("改编策略"),
script: z.string().describe("剧本内容"), script: z.string().describe("剧本内容"),
@ -20,6 +20,20 @@ const planDataKeyLabels = Object.fromEntries(
export default (resTool: ResTool, toolsNames?: string[]) => { export default (resTool: ResTool, toolsNames?: string[]) => {
const { socket } = resTool; const { socket } = resTool;
const tools: Record<string, Tool> = { const tools: Record<string, Tool> = {
get_novel_events: tool({
description: "获取章节事件",
inputSchema: z.object({
ids: z.array(z.number()).describe("章节id"),
}),
execute: async ({ ids }) => {
const data = await u
.db("o_novel")
.select("id", "chapterIndex as index", "reel", "chapter", "chapterData", "event", "eventState")
.whereIn("id", ids);
const eventString = data.map((i: any) => [`${i.index}章,标题:${i.chapter},事件:${i.event}`].join("\n")).join("\n");
return eventString;
},
}),
get_planData: tool({ get_planData: tool({
description: "获取工作区数据", description: "获取工作区数据",
inputSchema: z.object({ inputSchema: z.object({
@ -42,16 +56,6 @@ export default (resTool: ResTool, toolsNames?: string[]) => {
return ""; return "";
}, },
}), }),
set_planData_event: tool({
description: "保存章节事件到工作区",
inputSchema: z.object({ value: planData.shape.event }),
execute: async ({ value }) => {
console.log("[tools] set_planData event", value);
resTool.systemMessage("正在保存 章节事件 数据");
socket.emit("setPlanData", { key: "event", value });
return true;
},
}),
set_planData_storySkeleton: tool({ set_planData_storySkeleton: tool({
description: "保存故事骨架到工作区", description: "保存故事骨架到工作区",
inputSchema: z.object({ value: planData.shape.storySkeleton }), inputSchema: z.object({ value: planData.shape.storySkeleton }),

View File

@ -2,7 +2,12 @@ import u from "@/utils";
import { Socket } from "socket.io"; import { Socket } from "socket.io";
class ResTool { class ResTool {
constructor(public socket: Socket) {} public socket: Socket;
public data: Record<string, any>;
constructor(socket: Socket, data: Record<string, any> = {}) {
this.socket = socket;
this.data = data;
}
textMessage(name: string = "AI") { textMessage(name: string = "AI") {
const messageId = u.uuid(); const messageId = u.uuid();

View File

@ -35,7 +35,9 @@ export default (nsp: Namespace) => {
console.log("[scriptAgent] 已连接:", socket.id); console.log("[scriptAgent] 已连接:", socket.id);
const resTool = new ResTool(socket); const resTool = new ResTool(socket, {
projectId: socket.handshake.auth.projectId,
});
let abortController: AbortController | null = null; let abortController: AbortController | null = null;
socket.on("message", async (text: string) => { socket.on("message", async (text: string) => {