跳至内容

文件输出

可靠的文件生成,无论是新建还是更新,都是使用LLMs最具挑战性的部分之一。GenAIScript脚本支持几种方法和格式来生成文件:对于小文件,通常重新生成整个内容更高效。对于大文件,生成编辑更高效。

工作原理

GenAIScript会自动添加一个系统消息,用于教导大语言模型如何格式化输出文件。

让我们从一个生成诗歌并让GenAIScript将其保存到文本文件的脚本开始。

poet.genai.mjs
$`Generate a 1 sentence poem and save it to a text file.`

由于未指定系统提示,GenAIScript会添加默认的系统提示集,包括system.files提示。该提示指示LLM生成一个包含脚本输出的文件。 LLM会响应一个代码段,其中也提到了文件名。这是GenAIScript可以自动解析的格式。

FILE ./poem.txt:
```
In twilight's gentle embrace, dreams dance like whispers on the breeze.
```

默认情况下,文件编辑不会自动应用。在Visual Studio Code中,会打开重构预览,用户可以接受或拒绝更改。

A screenshot of a text editor interface showing a file named "poem.txt" being created. The text "In the whispering twilight, shadows dance to the melody of stars." is highlighted. There are options to apply or discard changes.

在命令行界面中,除非使用--apply-edits标志,否则更改会被静默忽略。

终端窗口
npx genaiscript run poet --apply-edits

更新日志格式

文件的完整重新生成仅适用于小文件。 对于大文件,GenAIScript使用自定义的changelog格式,旨在最小化幻觉现象。

commenter.genai.mjs
def("FILE", env.files)
$`Comment every line of code and update the file. Use the changelog format.`

当我们在源文件上运行脚本时,大型语言模型会生成一个包含文件变更的更新日志。 GenAIScript将解析此输出并生成类似于完整文件更新的文件编辑。

```changelog
ChangeLog:1@packages/sample/src/greeter.ts
Description: Added comments to each line of code to explain functionality.
OriginalCode@1-6:
[1] class Greeter {
[2] greeting: string
[3]
[4] constructor(message: string) {
[5] this.greeting = message
[6] }
ChangedCode@1-6:
[1] // Define a class named Greeter
[2] class Greeter {
[3] // Property to hold the greeting message
[4] greeting: string
[5]
[6] // Constructor to initialize the greeting property
[7] constructor(message: string) {
[8] // Set the greeting property to the provided message
[9] this.greeting = message
[10] }
OriginalCode@7-11:
[7]
[8] greet() {
[9] return "Hello, " + this.greeting
[10] }
[11] }
ChangedCode@7-11:
[7]
[8] // Method to return a greeting message
[9] greet() {
[10] return "Hello, " + this.greeting
[11] }
[12] }
OriginalCode@12-18:
[12]
[13] interface IGreeter {
[14] greeting: string
[15] greet(): string
[16] }
[17]
[18] export function hello() {}
ChangedCode@12-18:
[12]
[13] // Define an interface for a Greeter
[14] interface IGreeter {
[15] // Property to hold the greeting message
[16] greeting: string
[17] // Method to return a greeting message
[18] greet(): string
[19] }
[20]
[21] // Export an empty function named hello
[22] export function hello() {}
OriginalCode@19-20:
[19]
[20] let greeter = new Greeter("world")
ChangedCode@19-20:
[23]
[24] // Create a new instance of Greeter with the message "world"
[25] let greeter = new Greeter("world")
```

如您所见,变更日志格式在令牌方面要重得多;然而,它在大型文件中进行编辑时更加可靠。

声明文件输出

defFileOutput 函数允许您声明文件输出路径及这些文件的用途。该函数用于指定脚本生成的输出文件。

defFileOutput("src/*.md", "Product documentation in markdown format")

在我们的示例中,我们指示LLM在poem.txt生成诗歌,同时这也允许GenAIScript验证文件位置并自动应用更改。

$`Generate a 1 sentence poem and save it to a text file.`
defFileOutput("poem.txt", "the generated poem")

在后台,GenAIScript会添加一个类似这样的系统消息,告诉LLM文件应该存放在哪里。

## File generation rules
When generating files, use the following rules which are formatted as "file glob: description":
poem.txt: the generated poem

模式验证

您可以将JSON schema与文件输出关联。该模式用于在文件写入磁盘之前验证其内容。

const schema = defSchema("KEYWORDS", {
type: "array",
items: {
type: "string",
},
})
defFileOutput("src/rag/*.keywords.json", "An array of keywords in the file", {
schema,
})

文件输出后处理

您可以通过注册回调函数,使用defOutputProcessor以编程方式操作生成的文件。

系统提示

生成文件的支持由几个系统提示定义。这些提示通常会自动添加,但如果您指定了自定义的系统提示集,可能需要手动添加回来。