1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
| import { chat, type AssistantMessage, type FinishReason, type Message, type Tool, type Usage, } from "@xsai/shared-chat"; import { tool } from "@xsai/tool"; import { message } from "@xsai/utils-chat"; import * as z from "zod";
export interface Choice { finish_reason: FinishReason; index: number; message: AssistantMessage; }
export interface ChatCompletionsResponse { choices: Choice[]; created: number; id: string; model: string; object: "chat.completion"; system_fingerprint: string; usage: Usage; }
export const assistant = message.assistant; export const system = message.system; export const user = message.user;
export function createAgent(options: { provider: { baseURL: string; apiKey: string; model: string; }; tools?: Tool[]; }) { async function call( messages: Message[], callOptions: { maxRoundTrip: number } = { maxRoundTrip: 10 } ) { let count = 0; while (count < callOptions.maxRoundTrip) { const res = await chat({ ...options.provider, baseURL: options.provider.baseURL, model: options.provider.model, messages, tools: options.tools, }); const cmplResp = (await res.json()) as ChatCompletionsResponse; console.log(JSON.stringify(cmplResp.choices[0], null, 2)); const toolCalls = cmplResp.choices[0]?.message.tool_calls; if (!toolCalls?.length) { return cmplResp; } messages.push(assistant(toolCalls[0])); for (const choice of cmplResp.choices) { if (!choice.message.tool_calls) { continue; } for (const toolCall of choice.message.tool_calls) { const foundTool = options.tools?.find( (tool) => tool.function.name === toolCall.function.name ); if (!foundTool) { continue; } const invokeResult = await foundTool.execute( JSON.parse(toolCall.function.arguments || "{}"), { messages, toolCallId: toolCall.id, } ); messages.push({ role: "tool", content: invokeResult === "string" ? invokeResult : JSON.stringify(invokeResult), tool_call_id: toolCall.id, }); } } count++; } } return { call }; }
async function main() { const getCity = await tool({ name: "getCity", description: "Get the user's city", execute: () => "广州", parameters: z.object({}), }); const getCityCode = await tool({ name: "getCityCode", description: "Get the user's city code with search", execute: () => "Guangzhou", parameters: z.object({ location: z .string() .min(1) .describe("Get the user's city code with search"), }), }); const getWeather = await tool({ name: "getWeather", description: "Get the city code weather", execute: ({ cityCode }) => ({ city: `广州`, cityCode, weather: "sunny", degreesCelsius: 26, }), parameters: z.object({ cityCode: z.string().min(1).describe("Get the city code weather"), }), }); const { call } = createAgent({ provider: { baseURL: "http://localhost:11434/v1", apiKey: "unused", model: "qwen3:8b", }, tools: [getCity, getCityCode, getWeather], }); const res = await call([ system( "我是一名乐于助人的助手,负责为用户提供所需信息。用户可能提出任何问题,请识别用户的需求,并选用合适的工具来获取必要信息。" ), user("今天天气怎么样?"), ]); console.log(res?.choices[0]?.message.content); }
main();
|