许多AI应用通过自然语言与用户交互。然而,某些用例要求模型使用结构化输入直接与外部系统(如API、数据库或文件系统)对接。
工具是智能体 调用以执行操作的组件。它们通过让模型与外部世界进行具有明确输入和输出的交互来扩展模型能力。工具封装了一个可调用函数及其输入模式。这些可以传递给兼容的聊天模型 ,允许模型决定是否调用工具以及使用什么参数。在这些场景中,工具调用使模型能够生成符合指定输入模式的请求。
创建工具
基础工具定义
创建工具最简单的方法是从 langchain 包中导入 tool 函数。您可以使用 zod 来定义工具的输入模式:
import * as z from "zod"
import { tool } from "langchain"
const searchDatabase = tool (
({ query , limit }) => `Found ${ limit } results for ' ${ query } '` ,
{
name: "search_database" ,
description: "Search the customer database for records matching the query." ,
schema: z . object ({
query: z . string (). describe ( "Search terms to look for" ),
limit: z . number (). describe ( "Maximum number of results to return" ),
}),
}
);
访问上下文
为何重要: 当工具能够访问智能体状态、运行时上下文和长期记忆时,它们才是最强大的。这使工具能够做出上下文感知的决策、个性化响应并在整个对话过程中维护信息。
工具可以通过 ToolRuntime 参数访问运行时信息,该参数提供:
状态 - 在执行过程中流动的可变数据(消息、计数器、自定义字段)
上下文 - 不可变配置,如用户ID、会话详细信息或特定于应用程序的配置
存储 - 跨对话的持久性长期记忆
流写入器 - 在工具执行时流式传输自定义更新
配置 - 运行的 RunnableConfig
工具调用 ID - 当前工具调用的 ID
使用 ToolRuntime 在单个参数中访问所有运行时信息。只需将 runtime: ToolRuntime 添加到您的工具签名中,它将被自动注入,而不会暴露给 LLM。
ToolRuntime :一个统一的参数,为工具提供对状态、上下文、存储、流、配置和工具调用 ID 的访问。这取代了旧的使用单独的 @[InjectedState]、@[InjectedStore]、@[get_runtime] 和 @[InjectedToolCallId] 注解的模式。
上下文
通过 runtime.context 访问不可变配置和上下文数据,如用户ID、会话详细信息或特定于应用程序的配置。
工具可以通过 config 参数访问智能体的运行时上下文:
import * as z from "zod"
import { ChatOpenAI } from "@langchain/openai"
import { createAgent } from "langchain"
const getUserName = tool (
( _ , config ) => {
return config . context . user_name
},
{
name: "get_user_name" ,
description: "Get the user's name." ,
schema: z . object ({}),
}
);
const contextSchema = z . object ({
user_name: z . string (),
});
const agent = createAgent ({
model: new ChatOpenAI ({ model: "gpt-4o" }),
tools: [ getUserName ],
contextSchema ,
});
const result = await agent . invoke (
{
messages: [{ role: "user" , "content" : "What is my name?" }]
},
{
context: { user_name: "John Smith" }
}
);
记忆(存储)
使用存储访问跨对话的持久性数据。存储通过 runtime.store 访问,允许您保存和检索用户特定或应用程序特定的数据。
import * as z from "zod" ;
import { createAgent , tool } from "langchain" ;
import { InMemoryStore } from "@langchain/langgraph" ;
import { ChatOpenAI } from "@langchain/openai" ;
const store = new InMemoryStore ();
// Access memory
const getUserInfo = tool (
async ({ user_id }) => {
const value = await store . get ([ "users" ], user_id );
console . log ( "get_user_info" , user_id , value );
return value ;
},
{
name: "get_user_info" ,
description: "Look up user info." ,
schema: z . object ({
user_id: z . string (),
}),
}
);
// Update memory
const saveUserInfo = tool (
async ({ user_id , name , age , email }) => {
console . log ( "save_user_info" , user_id , name , age , email );
await store . put ([ "users" ], user_id , { name , age , email });
return "Successfully saved user info." ;
},
{
name: "save_user_info" ,
description: "Save user info." ,
schema: z . object ({
user_id: z . string (),
name: z . string (),
age: z . number (),
email: z . string (),
}),
}
);
const agent = createAgent ({
model: new ChatOpenAI ({ model: "gpt-4o" }),
tools: [ getUserInfo , saveUserInfo ],
store ,
});
// First session: save user info
await agent . invoke ({
messages: [
{
role: "user" ,
content: "Save the following user: userid: abc123, name: Foo, age: 25, email: [email protected] " ,
},
],
});
// Second session: get user info
const result = await agent . invoke ({
messages: [
{ role: "user" , content: "Get user info for user with id 'abc123'" },
],
});
console . log ( result );
// Here is the user info for user with ID "abc123":
// - Name: Foo
// - Age: 25
// - Email: [email protected]
See all 70 lines
流写入器
在工具执行时,使用 runtime.stream_writer 流式传输自定义更新。这对于向用户提供关于工具正在执行的操作的实时反馈非常有用。
import * as z from "zod" ;
import { tool } from "langchain" ;
const getWeather = tool (
({ city }, config ) => {
const writer = config . streamWriter ;
// Stream custom updates as the tool executes
writer ( `Looking up data for city: ${ city } ` );
writer ( `Acquired data for city: ${ city } ` );
return `It's always sunny in ${ city } !` ;
},
{
name: "get_weather" ,
description: "Get weather for a given city." ,
schema: z . object ({
city: z . string (),
}),
}
);