跳至主要内容

如何流式传输工具调用

在流式上下文中调用工具时,消息块 将通过 .tool_call_chunks 属性填充 工具调用块 对象的列表。ToolCallChunk 包含工具的可选字符串字段 nameargsid,并包含一个可选的整数字段 index,该字段可用于将块连接在一起。字段是可选的,因为工具调用的部分可能跨越不同的块流式传输(例如,包含参数子字符串的块可能为工具名称和 ID 具有空值)。

由于消息块继承自其父消息类,因此包含工具调用块的 AIMessageChunk 也将包含 .tool_calls.invalid_tool_calls 字段。这些字段是根据消息的工具调用块进行最佳努力解析的。

请注意,并非所有提供商目前都支持工具调用的流式传输。在开始之前,让我们定义工具和模型。

import { z } from "zod";
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";

const addTool = tool(
async (input) => {
return input.a + input.b;
},
{
name: "add",
description: "Adds a and b.",
schema: z.object({
a: z.number(),
b: z.number(),
}),
}
);

const multiplyTool = tool(
async (input) => {
return input.a * input.b;
},
{
name: "multiply",
description: "Multiplies a and b.",
schema: z.object({
a: z.number(),
b: z.number(),
}),
}
);

const tools = [addTool, multiplyTool];

const model = new ChatOpenAI({
model: "gpt-4o",
temperature: 0,
});

const modelWithTools = model.bindTools(tools);

现在,让我们定义查询并流式传输输出

const query = "What is 3 * 12? Also, what is 11 + 49?";

const stream = await modelWithTools.stream(query);

for await (const chunk of stream) {
console.log(chunk.tool_call_chunks);
}
[]
[
{
name: 'multiply',
args: '',
id: 'call_MdIlJL5CAYD7iz9gTm5lwWtJ',
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: '{"a"',
id: undefined,
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: ': 3, ',
id: undefined,
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: '"b": 1',
id: undefined,
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: '2}',
id: undefined,
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: 'add',
args: '',
id: 'call_ihL9W6ylSRlYigrohe9SClmW',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: '{"a"',
id: undefined,
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: ': 11,',
id: undefined,
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: ' "b": ',
id: undefined,
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: undefined,
args: '49}',
id: undefined,
index: 1,
type: 'tool_call_chunk'
}
]
[]
[]

请注意,添加消息块将合并其相应的工具调用块。这是 LangChain 的各种 工具输出解析器 支持流式传输的原理。

例如,在下面,我们将累积工具调用块

import { concat } from "@langchain/core/utils/stream";

const stream = await modelWithTools.stream(query);

let gathered = undefined;

for await (const chunk of stream) {
gathered = gathered !== undefined ? concat(gathered, chunk) : chunk;
console.log(gathered.tool_call_chunks);
}
[]
[
{
name: 'multiply',
args: '',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a"',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, ',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 1',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '{"a"',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '{"a": 11,',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '{"a": 11, "b": ',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '{"a": 11, "b": 49}',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '{"a": 11, "b": 49}',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]
[
{
name: 'multiply',
args: '{"a": 3, "b": 12}',
id: 'call_0zGpgVz81Ew0HA4oKblG0s0a',
index: 0,
type: 'tool_call_chunk'
},
{
name: 'add',
args: '{"a": 11, "b": 49}',
id: 'call_ufY7lDSeCQwWbdq1XQQ2PBHR',
index: 1,
type: 'tool_call_chunk'
}
]

最后,我们可以看到最终的聚合工具调用块包含完全收集的原始字符串值

console.log(typeof gathered.tool_call_chunks[0].args);
string

我们还可以看到最后完全解析的工具调用是一个对象

console.log(typeof gathered.tool_calls[0].args);
object

此页面对您有帮助吗?


您也可以在 GitHub 上留下详细的反馈 GitHub.